Compare commits

..

43 Commits

Author SHA1 Message Date
github-actions[bot]
bf67cfbeff chore: update github-versions.json 2026-03-10 18:17:10 +00:00
CanbiZ (MickLesk)
c69c4afd25 update rybbit link 2026-03-10 16:56:47 +01:00
Michel Roegl-Brunner
516d8d7a0f toggle is_dev to false when a new script gets merged 2026-03-10 16:07:51 +01:00
Michel Roegl-Brunner
a0c93900e9 Remove unnecessary blank line in 2fauth.sh 2026-03-10 15:45:15 +01:00
Michel Roegl-Brunner
a11f282a43 Update workflow 2026-03-10 15:44:28 +01:00
Michel Roegl-Brunner
cac6b4ec59 Check workflow to update date in Pocketbase 2026-03-10 15:39:07 +01:00
Michel Roegl-Brunner
eba96a55d2 New workflow to update last updated field in Database when a script gets changed, also adds last_update_link to link to the latest changes 2026-03-10 15:33:15 +01:00
Michel Roegl-Brunner
37f4585110 New workflow to update last updated field in Database when a script gets changed, also adds last_update_link to link to the latest changes 2026-03-10 15:33:15 +01:00
community-scripts-pr-app[bot]
e6931434b0 Update CHANGELOG.md (#12745)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-10 14:23:26 +00:00
Chris
eec763bed0 [Fix] Immich: Pin libvips to 8.17.3 (#12744) 2026-03-10 15:22:48 +01:00
community-scripts-pr-app[bot]
fa62363628 chore: update github-versions.json (#12743)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-10 12:12:48 +00:00
community-scripts-pr-app[bot]
0bbb5a1c74 chore: update github-versions.json (#12741)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-10 06:15:50 +00:00
community-scripts-pr-app[bot]
064e440d00 Update CHANGELOG.md (#12737)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-10 00:19:06 +00:00
community-scripts-pr-app[bot]
129b85a8cf chore: update github-versions.json (#12736)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-10 00:18:44 +00:00
community-scripts-pr-app[bot]
586154d4e1 Update CHANGELOG.md (#12734)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-09 22:27:24 +00:00
Bram
b819231a01 feat: add CopycatWarningToast component for user warnings (#12733)
Introduced a new CopycatWarningToast component that displays a warning about copycat sites. The toast appears at the top-center of the screen and can be dismissed, with the dismissal state stored in local storage to prevent reappearing. Integrated the component into the RootLayout for global visibility.
2026-03-09 23:27:01 +01:00
community-scripts-pr-app[bot]
3ec9eba736 chore: update github-versions.json (#12732)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-09 18:17:57 +00:00
community-scripts-pr-app[bot]
75d4bc2b61 Update CHANGELOG.md (#12731)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-09 17:59:58 +00:00
Chris
a5ac56be7a [Hotfix] qBittorrent: Disable UPnP port forwarding by default (#12728) 2026-03-09 18:59:35 +01:00
community-scripts-pr-app[bot]
fe46d8c22d Update CHANGELOG.md (#12730)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-09 17:39:24 +00:00
Chris
93cbd51d5b [Quickfix] Opencloud: ensure correct case for binary (#12729) 2026-03-09 18:38:58 +01:00
CanbiZ (MickLesk)
0b99873194 Add dependency check for zstd before backup
Ensure zstd dependency is installed before backup.
2026-03-09 18:36:28 +01:00
community-scripts-pr-app[bot]
8113c7da22 Update CHANGELOG.md (#12726)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-09 16:06:44 +00:00
CanbiZ (MickLesk)
85023dab51 Omada: Bump libssl (#12724) 2026-03-09 17:06:07 +01:00
community-scripts-pr-app[bot]
f8ab3dc4b9 Update CHANGELOG.md (#12722)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-09 14:23:41 +00:00
Chris
fedabe4889 Pin Opencloud to 5.2.0 (#12721) 2026-03-09 15:23:07 +01:00
community-scripts-pr-app[bot]
eba19d8e42 Update CHANGELOG.md (#12718)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-09 12:52:21 +00:00
CanbiZ (MickLesk)
e180a3bc44 openwebui: Ensure required dependencies (#12717)
* openwebui: Ensure required dependencies

Added zstd and build-essential as dependencies for the script.

* Update dependencies in openwebui-install.sh

Added build-essential and libmariadb-dev to dependencies.
2026-03-09 13:51:59 +01:00
community-scripts-pr-app[bot]
a1a465708f Update CHANGELOG.md (#12716)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-09 12:24:37 +00:00
CanbiZ (MickLesk)
346d6c6a0a feat: improve zigbee2mqtt backup handler (#12714)
- Name backups by installed version (e.g. Zigbee2MQTT_backup_2.5.1.tar.zst)
- Use zstd compression instead of gzip
- Keep last 5 backups instead of deleting all previous ones
2026-03-09 13:24:09 +01:00
community-scripts-pr-app[bot]
c76813cbcb chore: update github-versions.json (#12715)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-09 12:12:25 +00:00
CanbiZ (MickLesk)
e7f551dab6 fix(hwaccel): install ROCm runtime only, reduce disk resize to +4GB
The full 'rocm' meta-package includes 15GB+ of dev tools (compilers,
debuggers, dev headers) which are unnecessary in LXC containers.
Install only runtime packages: rocm-opencl-runtime, rocm-hip-runtime,
rocm-smi-lib. Reduce disk resize from +8GB to +4GB accordingly.
2026-03-09 11:14:26 +01:00
CanbiZ (MickLesk)
d8b2a37228 fix(build): auto-resize disk +8GB when AMD GPU detected for ROCm 2026-03-09 10:18:23 +01:00
community-scripts-pr-app[bot]
af3950fafc Update CHANGELOG.md (#12710)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-09 09:03:30 +00:00
CanbiZ (MickLesk)
b20bf9c658 tools: add Alpine (apk) support to ensure_dependencies and is_package_installed (#12703) 2026-03-09 10:03:04 +01:00
CanbiZ (MickLesk)
8c5e340ad0 fix(hwaccel): use amdgpu/latest/ubuntu instead of versioned URL 2026-03-09 09:57:28 +01:00
community-scripts-pr-app[bot]
f3cd063816 Update CHANGELOG.md (#12709)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-09 08:48:16 +00:00
CanbiZ (MickLesk)
5adfa3cb45 Frigate: try an OpenVino model build fallback (#12704)
Co-authored-by: Tobias <96661824+CrazyWolf13@users.noreply.github.com>
2026-03-09 09:47:50 +01:00
community-scripts-pr-app[bot]
3398fe9361 Update CHANGELOG.md (#12708)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-09 08:37:47 +00:00
CanbiZ (MickLesk)
2afc25d51f tools.func: extend hwaccel with ROCm (#12707) 2026-03-09 09:37:26 +01:00
CanbiZ (MickLesk)
8c5d5c6679 Downgrade Node.js version from 24 to 22 2026-03-09 09:13:45 +01:00
community-scripts-pr-app[bot]
fca66c5b56 Update CHANGELOG.md (#12706)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-09 08:05:40 +00:00
CanbiZ (MickLesk)
d38ca1a7fc Reactive Resume: rewrite for v5 using original repo amruthpilla/reactive-resume (#12705)
* fix(reactive-resume): rewrite for v5 using original repo amruthpillai/reactive-resume

Replaces lazy-media fork with original upstream repo (amruthpillai/reactive-resume).
Rewrites install script for v5 architecture:
- TanStack Start / Drizzle ORM single-package build
- Headless Chromium for PDF generation (replaces Browserless)
- Local filesystem storage (removes MinIO dependency)
- Node 24 + pnpm
- Runtime: node .output/server/index.mjs

Fixes #12672, Fixes #11651

* add clean_install
2026-03-09 09:05:14 +01:00
20 changed files with 592 additions and 83 deletions

View File

@@ -6,14 +6,14 @@ on:
jobs:
close_issue:
if: github.event.pull_request.merged == true && github.repository == 'community-scripts/ProxmoxVE'
runs-on: ubuntu-latest
runs-on: self-hosted
steps:
- name: Checkout target repo (main)
- name: Checkout target repo (merge commit)
uses: actions/checkout@v4
with:
repository: community-scripts/ProxmoxVE
ref: main
ref: ${{ github.event.pull_request.merge_commit_sha }}
token: ${{ secrets.GITHUB_TOKEN }}
- name: Extract and Process PR Title
@@ -23,6 +23,39 @@ jobs:
echo "Processed Title: $title"
echo "title=$title" >> $GITHUB_ENV
- name: Get slugs from merged PR
id: get_slugs
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
pr_files=$(gh pr view ${{ github.event.pull_request.number }} --repo community-scripts/ProxmoxVE --json files -q '.files[].path' 2>/dev/null || true)
slugs=""
for path in $pr_files; do
[[ -f "$path" ]] || continue
if [[ "$path" == frontend/public/json/*.json ]]; then
s=$(jq -r '.slug // empty' "$path" 2>/dev/null)
[[ -n "$s" ]] && slugs="$slugs $s"
elif [[ "$path" == ct/*.sh ]] || [[ "$path" == install/*.sh ]] || [[ "$path" == tools/*.sh ]] || [[ "$path" == turnkey/*.sh ]] || [[ "$path" == vm/*.sh ]]; then
base=$(basename "$path" .sh)
if [[ "$path" == install/* && "$base" == *-install ]]; then
s="${base%-install}"
else
s="$base"
fi
[[ -n "$s" ]] && slugs="$slugs $s"
fi
done
slugs=$(echo $slugs | xargs -n1 | sort -u | tr '\n' ' ')
if [[ -z "$slugs" && -n "$title" ]]; then
slugs="$title"
fi
if [[ -z "$slugs" ]]; then
echo "count=0" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "$slugs" > pocketbase_slugs.txt
echo "count=$(echo $slugs | wc -w)" >> "$GITHUB_OUTPUT"
- name: Search for Issues with Similar Titles
id: find_issue
env:
@@ -63,3 +96,104 @@ jobs:
run: |
gh issue comment $issue_number --repo community-scripts/ProxmoxVED --body "Merged with #${{ github.event.pull_request.number }} in ProxmoxVE"
gh issue close $issue_number --repo community-scripts/ProxmoxVED
- name: Set is_dev to false in PocketBase
if: steps.get_slugs.outputs.count != '0'
env:
POCKETBASE_URL: ${{ secrets.POCKETBASE_URL }}
POCKETBASE_COLLECTION: ${{ secrets.POCKETBASE_COLLECTION }}
POCKETBASE_ADMIN_EMAIL: ${{ secrets.POCKETBASE_ADMIN_EMAIL }}
POCKETBASE_ADMIN_PASSWORD: ${{ secrets.POCKETBASE_ADMIN_PASSWORD }}
PR_URL: ${{ github.server_url }}/${{ github.repository }}/pull/${{ github.event.pull_request.number }}
run: |
node << 'ENDSCRIPT'
(async function() {
const fs = require('fs');
const https = require('https');
const http = require('http');
const url = require('url');
function request(fullUrl, opts) {
return new Promise(function(resolve, reject) {
const u = url.parse(fullUrl);
const isHttps = u.protocol === 'https:';
const body = opts.body;
const options = {
hostname: u.hostname,
port: u.port || (isHttps ? 443 : 80),
path: u.path,
method: opts.method || 'GET',
headers: opts.headers || {}
};
if (body) options.headers['Content-Length'] = Buffer.byteLength(body);
const lib = isHttps ? https : http;
const req = lib.request(options, function(res) {
let data = '';
res.on('data', function(chunk) { data += chunk; });
res.on('end', function() {
resolve({ ok: res.statusCode >= 200 && res.statusCode < 300, statusCode: res.statusCode, body: data });
});
});
req.on('error', reject);
if (body) req.write(body);
req.end();
});
}
const raw = process.env.POCKETBASE_URL.replace(/\/$/, '');
const apiBase = /\/api$/i.test(raw) ? raw : raw + '/api';
const coll = process.env.POCKETBASE_COLLECTION;
const slugsText = fs.readFileSync('pocketbase_slugs.txt', 'utf8').trim();
const slugs = slugsText ? slugsText.split(/\s+/).filter(Boolean) : [];
if (slugs.length === 0) {
console.log('No slugs to update.');
return;
}
const authUrl = apiBase + '/collections/users/auth-with-password';
const authBody = JSON.stringify({
identity: process.env.POCKETBASE_ADMIN_EMAIL,
password: process.env.POCKETBASE_ADMIN_PASSWORD
});
const authRes = await request(authUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: authBody
});
if (!authRes.ok) {
throw new Error('Auth failed: ' + authRes.body);
}
const token = JSON.parse(authRes.body).token;
const recordsUrl = apiBase + '/collections/' + encodeURIComponent(coll) + '/records';
const prUrl = process.env.PR_URL || '';
for (const slug of slugs) {
const filter = "(slug='" + slug.replace(/'/g, "''") + "')";
const listRes = await request(recordsUrl + '?filter=' + encodeURIComponent(filter) + '&perPage=1', {
headers: { 'Authorization': token }
});
const list = JSON.parse(listRes.body);
const record = list.items && list.items[0];
if (!record) {
console.log('Slug not in DB, skipping: ' + slug);
continue;
}
const patchRes = await request(recordsUrl + '/' + record.id, {
method: 'PATCH',
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
body: JSON.stringify({
name: record.name || record.slug,
last_update_commit: prUrl,
is_dev: false
})
});
if (!patchRes.ok) {
console.warn('PATCH failed for slug ' + slug + ': ' + patchRes.body);
continue;
}
console.log('Set is_dev=false for slug: ' + slug);
}
console.log('Done.');
})().catch(e => { console.error(e); process.exit(1); });
ENDSCRIPT
shell: bash

View File

@@ -0,0 +1,167 @@
name: Update script timestamp on .sh changes
on:
push:
branches:
- main
paths:
- "ct/**/*.sh"
- "install/**/*.sh"
- "tools/**/*.sh"
- "turnkey/**/*.sh"
- "vm/**/*.sh"
jobs:
update-script-timestamp:
runs-on: self-hosted
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get changed .sh files and derive slugs
id: slugs
run: |
changed=$(git diff --name-only "${{ github.event.before }}" "${{ github.event.after }}" -- ct/ install/ tools/ turnkey/ vm/ | grep '\.sh$' || true)
if [[ -z "$changed" ]]; then
echo "No .sh files changed in ct/, install/, tools/, turnkey/, or vm/."
echo "count=0" >> "$GITHUB_OUTPUT"
exit 0
fi
declare -A seen
slugs=""
for f in $changed; do
[[ -f "$f" ]] || continue
base="${f##*/}"
base="${base%.sh}"
if [[ "$f" == install/* && "$base" == *-install ]]; then
slug="${base%-install}"
else
slug="$base"
fi
if [[ -z "${seen[$slug]:-}" ]]; then
seen[$slug]=1
slugs="$slugs $slug"
fi
done
slugs=$(echo $slugs | xargs -n1 | sort -u)
if [[ -z "$slugs" ]]; then
echo "No slugs to update."
echo "count=0" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "$slugs" > changed_slugs.txt
echo "count=$(echo "$slugs" | wc -w)" >> "$GITHUB_OUTPUT"
- name: Parse PR number from merge commit
id: pr
run: |
re='#([0-9]+)'
if [[ "$COMMIT_MSG" =~ $re ]]; then
echo "number=${BASH_REMATCH[1]}" >> "$GITHUB_OUTPUT"
else
echo "number=" >> "$GITHUB_OUTPUT"
fi
env:
COMMIT_MSG: ${{ github.event.head_commit.message }}
- name: Update script timestamps in PocketBase
if: steps.slugs.outputs.count != '0'
env:
POCKETBASE_URL: ${{ secrets.POCKETBASE_URL }}
POCKETBASE_COLLECTION: ${{ secrets.POCKETBASE_COLLECTION }}
POCKETBASE_ADMIN_EMAIL: ${{ secrets.POCKETBASE_ADMIN_EMAIL }}
POCKETBASE_ADMIN_PASSWORD: ${{ secrets.POCKETBASE_ADMIN_PASSWORD }}
COMMIT_URL: ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}
PR_URL: ${{ steps.pr.outputs.number != '' && format('{0}/{1}/pull/{2}', github.server_url, github.repository, steps.pr.outputs.number) || '' }}
run: |
node << 'ENDSCRIPT'
(async function() {
const fs = require('fs');
const https = require('https');
const http = require('http');
const url = require('url');
function request(fullUrl, opts) {
return new Promise(function(resolve, reject) {
const u = url.parse(fullUrl);
const isHttps = u.protocol === 'https:';
const body = opts.body;
const options = {
hostname: u.hostname,
port: u.port || (isHttps ? 443 : 80),
path: u.path,
method: opts.method || 'GET',
headers: opts.headers || {}
};
if (body) options.headers['Content-Length'] = Buffer.byteLength(body);
const lib = isHttps ? https : http;
const req = lib.request(options, function(res) {
let data = '';
res.on('data', function(chunk) { data += chunk; });
res.on('end', function() {
resolve({ ok: res.statusCode >= 200 && res.statusCode < 300, statusCode: res.statusCode, body: data });
});
});
req.on('error', reject);
if (body) req.write(body);
req.end();
});
}
const raw = process.env.POCKETBASE_URL.replace(/\/$/, '');
const apiBase = /\/api$/i.test(raw) ? raw : raw + '/api';
const coll = process.env.POCKETBASE_COLLECTION;
const slugsText = fs.readFileSync('changed_slugs.txt', 'utf8').trim();
const slugs = slugsText ? slugsText.split(/\s+/).filter(Boolean) : [];
if (slugs.length === 0) {
console.log('No slugs to update.');
return;
}
const authUrl = apiBase + '/collections/users/auth-with-password';
const authBody = JSON.stringify({
identity: process.env.POCKETBASE_ADMIN_EMAIL,
password: process.env.POCKETBASE_ADMIN_PASSWORD
});
const authRes = await request(authUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: authBody
});
if (!authRes.ok) {
throw new Error('Auth failed: ' + authRes.body);
}
const token = JSON.parse(authRes.body).token;
const recordsUrl = apiBase + '/collections/' + encodeURIComponent(coll) + '/records';
for (const slug of slugs) {
const filter = "(slug='" + slug.replace(/'/g, "''") + "')";
const listRes = await request(recordsUrl + '?filter=' + encodeURIComponent(filter) + '&perPage=1', {
headers: { 'Authorization': token }
});
const list = JSON.parse(listRes.body);
const record = list.items && list.items[0];
if (!record) {
console.log('Slug not in DB, skipping: ' + slug);
continue;
}
const patchRes = await request(recordsUrl + '/' + record.id, {
method: 'PATCH',
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
body: JSON.stringify({
name: record.name || record.slug,
last_update_commit: process.env.PR_URL || process.env.COMMIT_URL || ''
})
});
if (!patchRes.ok) {
console.warn('PATCH failed for slug ' + slug + ': ' + patchRes.body);
continue;
}
console.log('Updated timestamp for slug: ' + slug);
}
console.log('Done.');
})().catch(e => { console.error(e); process.exit(1); });
ENDSCRIPT
shell: bash

View File

@@ -420,15 +420,51 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details>
## 2026-03-09
## 2026-03-10
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- [Fix] Immich: Pin libvips to 8.17.3 [@vhsdream](https://github.com/vhsdream) ([#12744](https://github.com/community-scripts/ProxmoxVE/pull/12744))
## 2026-03-09
### 🚀 Updated Scripts
- Pin Opencloud to 5.2.0 [@vhsdream](https://github.com/vhsdream) ([#12721](https://github.com/community-scripts/ProxmoxVE/pull/12721))
- #### 🐞 Bug Fixes
- [Hotfix] qBittorrent: Disable UPnP port forwarding by default [@vhsdream](https://github.com/vhsdream) ([#12728](https://github.com/community-scripts/ProxmoxVE/pull/12728))
- [Quickfix] Opencloud: ensure correct case for binary [@vhsdream](https://github.com/vhsdream) ([#12729](https://github.com/community-scripts/ProxmoxVE/pull/12729))
- Omada: Bump libssl [@MickLesk](https://github.com/MickLesk) ([#12724](https://github.com/community-scripts/ProxmoxVE/pull/12724))
- openwebui: Ensure required dependencies [@MickLesk](https://github.com/MickLesk) ([#12717](https://github.com/community-scripts/ProxmoxVE/pull/12717))
- Frigate: try an OpenVino model build fallback [@MickLesk](https://github.com/MickLesk) ([#12704](https://github.com/community-scripts/ProxmoxVE/pull/12704))
- Change cronjob setup to use www-data user [@opastorello](https://github.com/opastorello) ([#12695](https://github.com/community-scripts/ProxmoxVE/pull/12695))
- RustDesk Server: Fix check_for_gh_release function call [@tremor021](https://github.com/tremor021) ([#12694](https://github.com/community-scripts/ProxmoxVE/pull/12694))
- #### ✨ New Features
- feat: improve zigbee2mqtt backup handler [@MickLesk](https://github.com/MickLesk) ([#12714](https://github.com/community-scripts/ProxmoxVE/pull/12714))
- #### 💥 Breaking Changes
- Reactive Resume: rewrite for v5 using original repo amruthpilla/reactive-resume [@MickLesk](https://github.com/MickLesk) ([#12705](https://github.com/community-scripts/ProxmoxVE/pull/12705))
### 💾 Core
- #### ✨ New Features
- tools: add Alpine (apk) support to ensure_dependencies and is_package_installed [@MickLesk](https://github.com/MickLesk) ([#12703](https://github.com/community-scripts/ProxmoxVE/pull/12703))
- tools.func: extend hwaccel with ROCm [@MickLesk](https://github.com/MickLesk) ([#12707](https://github.com/community-scripts/ProxmoxVE/pull/12707))
### 🌐 Website
- #### ✨ New Features
- feat: add CopycatWarningToast component for user warnings [@BramSuurdje](https://github.com/BramSuurdje) ([#12733](https://github.com/community-scripts/ProxmoxVE/pull/12733))
## 2026-03-08
### 🚀 Updated Scripts

View File

@@ -380,7 +380,7 @@ function compile_imagemagick() {
function compile_libvips() {
SOURCE=$SOURCE_DIR/libvips
: "${LIBVIPS_REVISION:=$(jq -cr '.revision' "$BASE_DIR"/server/sources/libvips.json)}"
LIBVIPS_REVISION="0c9151a4f416d2f8ae20a755db218f6637050eec"
if [[ "$LIBVIPS_REVISION" != "$(grep 'libvips' ~/.immich_library_revisions | awk '{print $2}')" ]]; then
msg_info "Recompiling libvips"
[[ -d "$SOURCE" ]] && rm -rf "$SOURCE"

View File

@@ -29,7 +29,7 @@ function update_script() {
exit
fi
RELEASE="v5.1.0"
RELEASE="v5.2.0"
if check_for_gh_release "OpenCloud" "opencloud-eu/opencloud" "${RELEASE}"; then
msg_info "Stopping services"
systemctl stop opencloud opencloud-wopi
@@ -41,7 +41,9 @@ function update_script() {
ensure_dependencies "inotify-tools"
msg_ok "Updated packages"
rm -f /usr/bin/{OpenCloud,opencloud}
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "OpenCloud" "opencloud-eu/opencloud" "singlefile" "${RELEASE}" "/usr/bin" "opencloud-*-linux-amd64"
mv /usr/bin/OpenCloud /usr/bin/opencloud
if ! grep -q 'POSIX_WATCH' /etc/opencloud/opencloud.env; then
sed -i '/^## External/i ## Uncomment below to enable PosixFS Collaborative Mode\

View File

@@ -25,6 +25,8 @@ function update_script() {
check_container_storage
check_container_resources
ensure_dependencies zstd build-essential libmariadb-dev
if [[ -d /opt/open-webui ]]; then
msg_warn "Legacy installation detected — migrating to uv based install..."
msg_info "Stopping Service"
@@ -92,7 +94,6 @@ EOF
OLLAMA_VERSION=$(ollama -v | awk '{print $NF}')
RELEASE=$(curl -s https://api.github.com/repos/ollama/ollama/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4)}')
if [ "$OLLAMA_VERSION" != "$RELEASE" ]; then
ensure_dependencies zstd
msg_info "Ollama update available: v$OLLAMA_VERSION -> v$RELEASE"
msg_info "Downloading Ollama v$RELEASE \n"
curl -fS#LO https://github.com/ollama/ollama/releases/download/v${RELEASE}/ollama-linux-amd64.tar.zst

View File

@@ -35,13 +35,16 @@ function update_script() {
msg_ok "Stopped Service"
msg_info "Creating Backup"
rm -rf /opt/${APP}_backup*.tar.gz
mkdir -p /opt/z2m_backup
$STD tar -czf /opt/z2m_backup/${APP}_backup_$(date +%Y%m%d%H%M%S).tar.gz -C /opt zigbee2mqtt
mv /opt/zigbee2mqtt/data /opt/z2m_backup
msg_ok "Backup Created"
ensure_dependencies zstd
mkdir -p /opt/{backups,z2m_backup}
BACKUP_VERSION="$(<"$HOME/.zigbee2mqtt")"
BACKUP_FILE="/opt/backups/${APP}_backup_${BACKUP_VERSION}.tar.zst"
$STD tar -cf - -C /opt zigbee2mqtt | zstd -q -o "$BACKUP_FILE"
ls -t /opt/backups/${APP}_backup_*.tar.zst 2>/dev/null | tail -n +6 | xargs -r rm -f
mv /opt/zigbee2mqtt/data /opt/z2m_backup/data
msg_ok "Backup Created (${BACKUP_VERSION})"
fetch_and_deploy_gh_release "Zigbee2MQTT" "Koenkk/zigbee2mqtt" "tarball" "latest" "/opt/zigbee2mqtt"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Zigbee2MQTT" "Koenkk/zigbee2mqtt" "tarball" "latest" "/opt/zigbee2mqtt"
msg_info "Updating Zigbee2MQTT"
rm -rf /opt/zigbee2mqtt/data

View File

@@ -1,5 +1,5 @@
{
"generated": "2026-03-09T06:22:44Z",
"generated": "2026-03-10T18:17:10Z",
"versions": [
{
"slug": "2fauth",
@@ -11,9 +11,9 @@
{
"slug": "adguard",
"repo": "AdguardTeam/AdGuardHome",
"version": "v0.107.72",
"version": "v0.107.73",
"pinned": false,
"date": "2026-02-19T15:37:49Z"
"date": "2026-03-10T17:23:23Z"
},
{
"slug": "adguardhome-sync",
@@ -116,9 +116,9 @@
{
"slug": "bentopdf",
"repo": "alam00000/bentopdf",
"version": "v2.4.1",
"version": "v2.5.0",
"pinned": false,
"date": "2026-03-07T09:14:39Z"
"date": "2026-03-10T08:40:54Z"
},
{
"slug": "beszel",
@@ -200,9 +200,9 @@
{
"slug": "cleanuparr",
"repo": "Cleanuparr/Cleanuparr",
"version": "v2.7.7",
"version": "v2.7.8",
"pinned": false,
"date": "2026-03-02T13:08:32Z"
"date": "2026-03-10T16:03:47Z"
},
{
"slug": "cloudreve",
@@ -228,9 +228,9 @@
{
"slug": "configarr",
"repo": "raydak-labs/configarr",
"version": "v1.23.0",
"version": "v1.24.0",
"pinned": false,
"date": "2026-02-23T12:28:13Z"
"date": "2026-03-09T15:16:08Z"
},
{
"slug": "convertx",
@@ -473,9 +473,9 @@
{
"slug": "gokapi",
"repo": "Forceu/Gokapi",
"version": "v2.2.3",
"version": "v2.2.4",
"pinned": false,
"date": "2026-03-04T21:29:16Z"
"date": "2026-03-10T15:44:19Z"
},
{
"slug": "gotify",
@@ -557,9 +557,9 @@
{
"slug": "homebox",
"repo": "sysadminsmedia/homebox",
"version": "v0.24.1",
"version": "v0.24.2",
"pinned": false,
"date": "2026-03-07T15:41:21Z"
"date": "2026-03-09T19:54:02Z"
},
{
"slug": "homepage",
@@ -613,16 +613,16 @@
{
"slug": "invoiceninja",
"repo": "invoiceninja/invoiceninja",
"version": "v5.12.70",
"version": "v5.13.0",
"pinned": false,
"date": "2026-03-06T01:53:38Z"
"date": "2026-03-10T03:33:02Z"
},
{
"slug": "jackett",
"repo": "Jackett/Jackett",
"version": "v0.24.1323",
"version": "v0.24.1332",
"pinned": false,
"date": "2026-03-09T05:55:36Z"
"date": "2026-03-10T05:50:35Z"
},
{
"slug": "jellystat",
@@ -823,9 +823,9 @@
{
"slug": "mail-archiver",
"repo": "s1t5/mail-archiver",
"version": "2602.4",
"version": "2603.1",
"pinned": false,
"date": "2026-02-26T08:43:01Z"
"date": "2026-03-10T11:51:08Z"
},
{
"slug": "managemydamnlife",
@@ -837,9 +837,9 @@
{
"slug": "manyfold",
"repo": "manyfold3d/manyfold",
"version": "v0.133.1",
"version": "v0.134.0",
"pinned": false,
"date": "2026-02-26T15:50:34Z"
"date": "2026-03-09T13:20:45Z"
},
{
"slug": "mealie",
@@ -998,9 +998,9 @@
{
"slug": "opencloud",
"repo": "opencloud-eu/opencloud",
"version": "v5.1.0",
"version": "v5.2.0",
"pinned": true,
"date": "2026-02-16T15:04:28Z"
"date": "2026-03-09T13:32:31Z"
},
{
"slug": "opengist",
@@ -1236,9 +1236,9 @@
{
"slug": "pulse",
"repo": "rcourtman/Pulse",
"version": "v5.1.22",
"version": "v5.1.23",
"pinned": false,
"date": "2026-03-08T12:24:34Z"
"date": "2026-03-09T22:22:12Z"
},
{
"slug": "pve-scripts-local",
@@ -1305,10 +1305,10 @@
},
{
"slug": "reactive-resume",
"repo": "lazy-media/Reactive-Resume",
"version": "v1.2.7",
"repo": "amruthpillai/reactive-resume",
"version": "v5.0.11",
"pinned": false,
"date": "2026-01-20T11:59:40Z"
"date": "2026-03-04T20:39:11Z"
},
{
"slug": "recyclarr",
@@ -1362,9 +1362,9 @@
{
"slug": "scanopy",
"repo": "scanopy/scanopy",
"version": "v0.14.16",
"version": "v0.14.17",
"pinned": false,
"date": "2026-03-08T06:39:25Z"
"date": "2026-03-09T05:04:49Z"
},
{
"slug": "scraparr",
@@ -1376,9 +1376,9 @@
{
"slug": "seaweedfs",
"repo": "seaweedfs/seaweedfs",
"version": "4.15",
"version": "4.16",
"pinned": false,
"date": "2026-03-05T06:30:30Z"
"date": "2026-03-10T06:11:05Z"
},
{
"slug": "seelf",
@@ -1397,9 +1397,9 @@
{
"slug": "semaphore",
"repo": "semaphoreui/semaphore",
"version": "v2.17.17",
"version": "v2.17.21",
"pinned": false,
"date": "2026-03-08T21:42:11Z"
"date": "2026-03-09T09:33:06Z"
},
{
"slug": "shelfmark",
@@ -1516,9 +1516,9 @@
{
"slug": "tasmoadmin",
"repo": "TasmoAdmin/TasmoAdmin",
"version": "v4.3.4",
"version": "v5.0.0",
"pinned": false,
"date": "2026-01-25T22:16:41Z"
"date": "2026-03-09T20:51:03Z"
},
{
"slug": "tautulli",
@@ -1551,9 +1551,9 @@
{
"slug": "thingsboard",
"repo": "thingsboard/thingsboard",
"version": "v4.3.0.1",
"version": "v4.3.1",
"pinned": false,
"date": "2026-02-03T12:39:14Z"
"date": "2026-03-10T09:25:25Z"
},
{
"slug": "threadfin",
@@ -1586,9 +1586,9 @@
{
"slug": "tracearr",
"repo": "connorgallopo/Tracearr",
"version": "v1.4.21",
"version": "v1.4.22",
"pinned": false,
"date": "2026-03-03T18:43:20Z"
"date": "2026-03-09T17:39:52Z"
},
{
"slug": "tracktor",
@@ -1670,9 +1670,9 @@
{
"slug": "uptimekuma",
"repo": "louislam/uptime-kuma",
"version": "2.2.0",
"version": "2.2.1",
"pinned": false,
"date": "2026-03-05T02:08:14Z"
"date": "2026-03-10T02:25:33Z"
},
{
"slug": "vaultwarden",
@@ -1712,9 +1712,9 @@
{
"slug": "wanderer",
"repo": "meilisearch/meilisearch",
"version": "v1.37.0",
"version": "v1.38.0",
"pinned": false,
"date": "2026-03-02T09:16:36Z"
"date": "2026-03-09T08:06:29Z"
},
{
"slug": "warracker",
@@ -1726,9 +1726,9 @@
{
"slug": "watcharr",
"repo": "sbondCo/Watcharr",
"version": "v3.0.0",
"version": "v3.0.1",
"pinned": false,
"date": "2026-03-04T09:29:14Z"
"date": "2026-03-09T11:33:44Z"
},
{
"slug": "watchyourlan",
@@ -1838,9 +1838,9 @@
{
"slug": "zoraxy",
"repo": "tobychui/zoraxy",
"version": "v3.3.2-rc2",
"version": "v3.3.2-rc3",
"pinned": false,
"date": "2026-02-27T03:31:25Z"
"date": "2026-03-09T13:56:45Z"
},
{
"slug": "zwave-js-ui",

View File

@@ -5,6 +5,7 @@ import { Inter } from "next/font/google";
import Script from "next/script";
import React from "react";
import { CopycatWarningToast } from "@/components/copycat-warning-toast";
import { ThemeProvider } from "@/components/theme-provider";
import { analytics, basePath } from "@/config/site-config";
import QueryProvider from "@/components/query-provider";
@@ -116,6 +117,7 @@ export default function RootLayout({
<div className="w-full max-w-[1440px] ">
{children}
<Toaster richColors />
<CopycatWarningToast />
</div>
</div>
<Footer />

View File

@@ -0,0 +1,24 @@
"use client";
import { useEffect } from "react";
import { toast } from "sonner";
const STORAGE_KEY = "copycat-warning-dismissed";
export function CopycatWarningToast() {
useEffect(() => {
if (typeof window === "undefined")
return;
if (localStorage.getItem(STORAGE_KEY) === "true")
return;
toast.warning("Beware of copycat sites. Always verify the URL is correct before trusting or running scripts.", {
position: "top-center",
duration: Number.POSITIVE_INFINITY,
closeButton: true,
onDismiss: () => localStorage.setItem(STORAGE_KEY, "true"),
});
}, []);
return null;
}

View File

@@ -45,8 +45,8 @@ export const navbarLinks = [
export const mostPopularScripts = ["post-pve-install", "docker", "homeassistant"];
export const analytics = {
url: "analytics.bramsuurd.nl",
token: "f9eee289f931",
url: "analytics.community-scripts.org",
token: "e9f14e1e7232",
};
export const AlertColors = {

View File

@@ -208,7 +208,7 @@ msg_info "Building OpenVino Model"
cd /models
wget -q http://download.tensorflow.org/models/object_detection/ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz
$STD tar -zxf ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz --no-same-owner
if $STD python3 /opt/frigate/docker/main/build_ov_model.py; then
if python3 /opt/frigate/docker/main/build_ov_model.py &>/dev/null; then
cp /models/ssdlite_mobilenet_v2.xml /openvino-model/
cp /models/ssdlite_mobilenet_v2.bin /openvino-model/
wget -q https://github.com/openvinotoolkit/open_model_zoo/raw/master/data/dataset_classes/coco_91cl_bkgr.txt -O /openvino-model/coco_91cl_bkgr.txt

View File

@@ -260,7 +260,7 @@ msg_ok "(4/5) Compiled imagemagick"
msg_info "(5/5) Compiling libvips"
SOURCE=$SOURCE_DIR/libvips
: "${LIBVIPS_REVISION:=$(jq -cr '.revision' $BASE_DIR/server/sources/libvips.json)}"
LIBVIPS_REVISION="0c9151a4f416d2f8ae20a755db218f6637050eec"
$STD git clone https://github.com/libvips/libvips.git "$SOURCE"
cd "$SOURCE"
$STD git reset --hard "$LIBVIPS_REVISION"

View File

@@ -28,7 +28,7 @@ fi
if ! dpkg -l | grep -q 'libssl1.1'; then
msg_info "Installing libssl (if needed)"
curl -fsSL "https://security.debian.org/debian-security/pool/updates/main/o/openssl/libssl1.1_1.1.1w-0+deb11u4_amd64.deb" -o "/tmp/libssl.deb"
curl -fsSL "https://security.debian.org/debian-security/pool/updates/main/o/openssl/libssl1.1_1.1.1w-0+deb11u5_amd64.deb" -o "/tmp/libssl.deb"
$STD dpkg -i /tmp/libssl.deb
rm -f /tmp/libssl.deb
msg_ok "Installed libssl1.1"

View File

@@ -64,7 +64,8 @@ $STD sudo -u cool coolconfig set-admin-password --user=admin --password="$COOLPA
echo "$COOLPASS" >~/.coolpass
msg_ok "Installed Collabora Online"
fetch_and_deploy_gh_release "opencloud" "opencloud-eu/opencloud" "singlefile" "v5.1.0" "/usr/bin" "opencloud-*-linux-amd64"
fetch_and_deploy_gh_release "OpenCloud" "opencloud-eu/opencloud" "singlefile" "v5.2.0" "/usr/bin" "opencloud-*-linux-amd64"
mv /usr/bin/OpenCloud /usr/bin/opencloud
msg_info "Configuring OpenCloud"
DATA_DIR="/var/lib/opencloud"

View File

@@ -16,7 +16,9 @@ update_os
msg_info "Installing Dependencies"
$STD apt install -y \
ffmpeg \
zstd
zstd \
build-essential \
libmariadb-dev
msg_ok "Installed Dependencies"
setup_hwaccel

View File

@@ -27,6 +27,9 @@ WebUI\Password_PBKDF2="@ByteArray(amjeuVrF3xRbgzqWQmes5A==:XK3/Ra9jUmqUc4RwzCtrh
WebUI\Port=8090
WebUI\UseUPnP=false
WebUI\Username=admin
[Network]
PortForwardingEnabled=false
EOF
msg_ok "Setup qBittorrent-nox"

View File

@@ -25,14 +25,10 @@ fetch_and_deploy_gh_release "reactive-resume" "amruthpillai/reactive-resume" "ta
msg_info "Building Reactive Resume (Patience)"
cd /opt/reactive-resume
export NODE_ENV="production"
export CI="true"
rm -f pnpm-lock.yaml
$STD pnpm install
$STD pnpm install --frozen-lockfile
$STD pnpm run build
# Workaround: Vite/Rolldown bundles tslib CJS→ESM with broken .default destructure
# see https://github.com/amruthpillai/reactive-resume/issues/2773
find .output/server -name '*.mjs' -exec \
sed -i 's/__toESM(require_tslib())).default/__toESM(require_tslib()))/g' {} +
mkdir -p /opt/reactive-resume/data
msg_ok "Built Reactive Resume"

View File

@@ -1853,7 +1853,7 @@ advanced_settings() {
# ═══════════════════════════════════════════════════════════════════════════
# STEP 2: Root Password
# ═══════════════════════════════════════════════════════════════════════<EFBFBD><EFBFBD><EFBFBD>══
# ════════════════════════════════════════<EFBFBD><EFBFBD><EFBFBD>═══════════════════════════════<EFBFBD><EFBFBD><EFBFBD>══
2)
if PW1=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "ROOT PASSWORD" \
@@ -3922,6 +3922,17 @@ EOF
configure_gpu_passthrough
configure_additional_devices
# Increase disk size for AMD ROCm runtime (~4GB extra needed)
if [[ "${GPU_TYPE:-}" == "AMD" ]]; then
local rocm_extra=4
local new_disk_size=$((PCT_DISK_SIZE + rocm_extra))
if pct resize "$CTID" rootfs "${new_disk_size}G" >/dev/null 2>&1; then
msg_ok "Disk resized ${PCT_DISK_SIZE}GB → ${new_disk_size}GB for ROCm"
else
msg_warn "Failed to resize disk for ROCm — installation may fail if space is insufficient"
fi
fi
# ============================================================================
# START CONTAINER AND INSTALL USERLAND
# ============================================================================

View File

@@ -969,13 +969,43 @@ verify_repo_available() {
}
# ------------------------------------------------------------------------------
# Ensure dependencies are installed (with apt update caching)
# Ensure dependencies are installed (with apt/apk update caching)
# Supports both Debian (apt/dpkg) and Alpine (apk) systems
# ------------------------------------------------------------------------------
ensure_dependencies() {
local deps=("$@")
local missing=()
# Fast batch check using dpkg-query (much faster than individual checks)
# Detect Alpine Linux
if [[ -f /etc/alpine-release ]]; then
for dep in "${deps[@]}"; do
if command -v "$dep" &>/dev/null; then
continue
fi
if apk info -e "$dep" &>/dev/null; then
continue
fi
missing+=("$dep")
done
if [[ ${#missing[@]} -gt 0 ]]; then
$STD apk add --no-cache "${missing[@]}" || {
local failed=()
for pkg in "${missing[@]}"; do
if ! $STD apk add --no-cache "$pkg" 2>/dev/null; then
failed+=("$pkg")
fi
done
if [[ ${#failed[@]} -gt 0 ]]; then
msg_error "Failed to install dependencies: ${failed[*]}"
return 1
fi
}
fi
return 0
fi
# Debian/Ubuntu: Fast batch check using dpkg-query
local installed_pkgs
installed_pkgs=$(dpkg-query -W -f='${Package}\n' 2>/dev/null | sort -u)
@@ -1072,11 +1102,15 @@ create_temp_dir() {
}
# ------------------------------------------------------------------------------
# Check if package is installed (faster than dpkg -l | grep)
# Check if package is installed (supports both Debian and Alpine)
# ------------------------------------------------------------------------------
is_package_installed() {
local package="$1"
dpkg-query -W -f='${Status}' "$package" 2>/dev/null | grep -q "^install ok installed$"
if [[ -f /etc/alpine-release ]]; then
apk info -e "$package" &>/dev/null
else
dpkg-query -W -f='${Status}' "$package" 2>/dev/null | grep -q "^install ok installed$"
fi
}
# ------------------------------------------------------------------------------
@@ -4512,9 +4546,8 @@ _setup_amd_gpu() {
fi
# Ubuntu includes AMD firmware in linux-firmware by default
# ROCm for compute (optional - large download)
# Uncomment if needed:
# $STD apt -y install rocm-opencl-runtime 2>/dev/null || true
# ROCm compute stack (OpenCL + HIP)
_setup_rocm "$os_id" "$os_codename"
msg_ok "AMD GPU configured"
}
@@ -4539,9 +4572,103 @@ _setup_amd_apu() {
$STD apt -y install firmware-amd-graphics 2>/dev/null || true
fi
# ROCm compute stack (OpenCL + HIP) - also works for many APUs
_setup_rocm "$os_id" "$os_codename"
msg_ok "AMD APU configured"
}
# ══════════════════════════════════════════════════════════════════════════════
# AMD ROCm Compute Setup
# Adds ROCm repository and installs the ROCm compute stack for AMD GPUs/APUs.
# Provides: OpenCL, HIP, rocm-smi, rocminfo
# Supported: Debian 12/13, Ubuntu 22.04/24.04 (amd64 only)
# ══════════════════════════════════════════════════════════════════════════════
_setup_rocm() {
local os_id="$1" os_codename="$2"
# Only amd64 is supported
if [[ "$(dpkg --print-architecture 2>/dev/null)" != "amd64" ]]; then
msg_warn "ROCm is only available for amd64 — skipping"
return 0
fi
local ROCM_VERSION="7.2"
local ROCM_REPO_CODENAME
# Map OS codename to ROCm repository codename (Ubuntu-based repos)
case "${os_id}-${os_codename}" in
debian-bookworm) ROCM_REPO_CODENAME="jammy" ;;
debian-trixie | debian-sid) ROCM_REPO_CODENAME="noble" ;;
ubuntu-jammy) ROCM_REPO_CODENAME="jammy" ;;
ubuntu-noble) ROCM_REPO_CODENAME="noble" ;;
*)
msg_warn "ROCm not supported on ${os_id} ${os_codename} — skipping"
return 0
;;
esac
msg_info "Installing ROCm ${ROCM_VERSION} compute stack"
# ROCm main repository (userspace compute libs)
setup_deb822_repo \
"rocm" \
"https://repo.radeon.com/rocm/rocm.gpg.key" \
"https://repo.radeon.com/rocm/apt/${ROCM_VERSION}" \
"${ROCM_REPO_CODENAME}" \
"main" \
"amd64" || {
msg_warn "Failed to add ROCm repository — skipping ROCm"
return 0
}
# AMDGPU driver repository (append to same keyring)
{
echo ""
echo "Types: deb"
echo "URIs: https://repo.radeon.com/amdgpu/latest/ubuntu"
echo "Suites: ${ROCM_REPO_CODENAME}"
echo "Components: main"
echo "Architectures: amd64"
echo "Signed-By: /etc/apt/keyrings/rocm.gpg"
} >>/etc/apt/sources.list.d/rocm.sources
# Pin ROCm packages to prefer radeon repo
cat <<EOF >/etc/apt/preferences.d/rocm-pin-600
Package: *
Pin: release o=repo.radeon.com
Pin-Priority: 600
EOF
$STD apt update
# Install only runtime packages — full 'rocm' meta-package includes 15GB+ dev tools
$STD apt install -y rocm-opencl-runtime rocm-hip-runtime rocm-smi-lib 2>/dev/null || {
msg_warn "ROCm runtime install failed — trying minimal set"
$STD apt install -y rocm-opencl-runtime rocm-smi-lib 2>/dev/null || msg_warn "ROCm minimal install also failed"
}
# Group membership for GPU access
usermod -aG render,video root 2>/dev/null || true
# Environment (PATH + LD_LIBRARY_PATH)
if [[ -d /opt/rocm ]]; then
cat <<'ENVEOF' >/etc/profile.d/rocm.sh
export PATH="\$PATH:/opt/rocm/bin"
export LD_LIBRARY_PATH="\${LD_LIBRARY_PATH:+\$LD_LIBRARY_PATH:}/opt/rocm/lib"
ENVEOF
chmod +x /etc/profile.d/rocm.sh
# Also make available for current session / systemd services
echo "/opt/rocm/lib" >/etc/ld.so.conf.d/rocm.conf
ldconfig 2>/dev/null || true
fi
if [[ -x /opt/rocm/bin/rocminfo ]]; then
msg_ok "ROCm ${ROCM_VERSION} installed"
else
msg_warn "ROCm installed but rocminfo not found — GPU may not be available in container"
fi
}
# ══════════════════════════════════════════════════════════════════════════════
# NVIDIA GPU Setup
# ══════════════════════════════════════════════════════════════════════════════