mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-03-19 16:33:01 +01:00
Compare commits
2 Commits
main
...
docs/websi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c582e37dc | ||
|
|
0071259e67 |
161
.github/changelogs/2026/03.md
generated
vendored
161
.github/changelogs/2026/03.md
generated
vendored
@@ -1,164 +1,3 @@
|
||||
## 2026-03-14
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Patchmon: remove v prefix from pinned version [@MickLesk](https://github.com/MickLesk) ([#12891](https://github.com/community-scripts/ProxmoxVE/pull/12891))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- tools.func: don't abort on AMD repo apt update failure [@MickLesk](https://github.com/MickLesk) ([#12890](https://github.com/community-scripts/ProxmoxVE/pull/12890))
|
||||
|
||||
## 2026-03-13
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Hotfix: Removed clean install usage from original script. [@nickheyer](https://github.com/nickheyer) ([#12870](https://github.com/community-scripts/ProxmoxVE/pull/12870))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Discopanel: V2 Support + Script rewrite [@nickheyer](https://github.com/nickheyer) ([#12763](https://github.com/community-scripts/ProxmoxVE/pull/12763))
|
||||
|
||||
### 🧰 Tools
|
||||
|
||||
- update-apps: fix restore path, add PBS support and improve restore messages [@omertahaoztop](https://github.com/omertahaoztop) ([#12528](https://github.com/community-scripts/ProxmoxVE/pull/12528))
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- fix(pve-privilege-converter): handle already stopped container in manage_states [@liuqitoday](https://github.com/liuqitoday) ([#12765](https://github.com/community-scripts/ProxmoxVE/pull/12765))
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Update: Docs/website metadata workflow [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#12858](https://github.com/community-scripts/ProxmoxVE/pull/12858))
|
||||
|
||||
## 2026-03-12
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- manyfold: fix incorrect port in upstream requests by forwarding original host [@anlopo](https://github.com/anlopo) ([#12812](https://github.com/community-scripts/ProxmoxVE/pull/12812))
|
||||
- SparkyFitness: install pnpm dependencies from workspace root [@MickLesk](https://github.com/MickLesk) ([#12792](https://github.com/community-scripts/ProxmoxVE/pull/12792))
|
||||
- n8n: add build-essential to update dependencies [@MickLesk](https://github.com/MickLesk) ([#12795](https://github.com/community-scripts/ProxmoxVE/pull/12795))
|
||||
- Frigate openvino labelmap patch [@semtex1987](https://github.com/semtex1987) ([#12751](https://github.com/community-scripts/ProxmoxVE/pull/12751))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Pin Patchmon to 1.4.2 [@vhsdream](https://github.com/vhsdream) ([#12789](https://github.com/community-scripts/ProxmoxVE/pull/12789))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- tools.func: correct PATH escaping in ROCm profile script [@MickLesk](https://github.com/MickLesk) ([#12793](https://github.com/community-scripts/ProxmoxVE/pull/12793))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- core: add mode=generated for unattended frontend installs [@MickLesk](https://github.com/MickLesk) ([#12807](https://github.com/community-scripts/ProxmoxVE/pull/12807))
|
||||
- core: validate storage availability when loading defaults [@MickLesk](https://github.com/MickLesk) ([#12794](https://github.com/community-scripts/ProxmoxVE/pull/12794))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- tools.func: support older NVIDIA driver versions with 2 segments (xxx.xxx) [@MickLesk](https://github.com/MickLesk) ([#12796](https://github.com/community-scripts/ProxmoxVE/pull/12796))
|
||||
|
||||
### 🧰 Tools
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Fix PBS microcode naming [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#12834](https://github.com/community-scripts/ProxmoxVE/pull/12834))
|
||||
|
||||
### 📂 Github
|
||||
|
||||
- Cleanup: remove old workflow files [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#12818](https://github.com/community-scripts/ProxmoxVE/pull/12818))
|
||||
- Cleanup: remove frontend, move JSONs to json/ top-level [@MickLesk](https://github.com/MickLesk) ([#12813](https://github.com/community-scripts/ProxmoxVE/pull/12813))
|
||||
|
||||
### ❔ Uncategorized
|
||||
|
||||
- Remove json files [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#12830](https://github.com/community-scripts/ProxmoxVE/pull/12830))
|
||||
|
||||
## 2026-03-11
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- fix: Init telemetry in addon scripts [@MickLesk](https://github.com/MickLesk) ([#12777](https://github.com/community-scripts/ProxmoxVE/pull/12777))
|
||||
- Tracearr: Increase default disk variable from 5 to 10 [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#12762](https://github.com/community-scripts/ProxmoxVE/pull/12762))
|
||||
- Fix Wireguard Dashboard update [@odin568](https://github.com/odin568) ([#12767](https://github.com/community-scripts/ProxmoxVE/pull/12767))
|
||||
|
||||
### 🧰 Tools
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- Coder-Code-Server: Check if config file exists [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#12758](https://github.com/community-scripts/ProxmoxVE/pull/12758))
|
||||
|
||||
## 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
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- [Fix] Immich: chown install dir before machine-learning update [@vhsdream](https://github.com/vhsdream) ([#12684](https://github.com/community-scripts/ProxmoxVE/pull/12684))
|
||||
- [Fix] Scanopy: Build generate-fixtures [@vhsdream](https://github.com/vhsdream) ([#12686](https://github.com/community-scripts/ProxmoxVE/pull/12686))
|
||||
- fix: rustdeskserver: use correct repo string [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12682](https://github.com/community-scripts/ProxmoxVE/pull/12682))
|
||||
- NZBGet: Fixes for RAR5 handling [@tremor021](https://github.com/tremor021) ([#12675](https://github.com/community-scripts/ProxmoxVE/pull/12675))
|
||||
|
||||
### 🌐 Website
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- LXC-Execute: Fix slug [@tremor021](https://github.com/tremor021) ([#12681](https://github.com/community-scripts/ProxmoxVE/pull/12681))
|
||||
|
||||
## 2026-03-07
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
10
.github/workflows/delete-pocketbase-entry-on-removal.yml
generated
vendored
10
.github/workflows/delete-pocketbase-entry-on-removal.yml
generated
vendored
@@ -75,8 +75,7 @@ jobs:
|
||||
const http = require('http');
|
||||
const url = require('url');
|
||||
|
||||
function request(fullUrl, opts, redirectCount) {
|
||||
redirectCount = redirectCount || 0;
|
||||
function request(fullUrl, opts) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
const u = url.parse(fullUrl);
|
||||
const isHttps = u.protocol === 'https:';
|
||||
@@ -91,13 +90,6 @@ jobs:
|
||||
if (body) options.headers['Content-Length'] = Buffer.byteLength(body);
|
||||
const lib = isHttps ? https : http;
|
||||
const req = lib.request(options, function(res) {
|
||||
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
||||
if (redirectCount >= 5) return reject(new Error('Too many redirects from ' + fullUrl));
|
||||
const redirectUrl = url.resolve(fullUrl, res.headers.location);
|
||||
res.resume();
|
||||
resolve(request(redirectUrl, opts, redirectCount + 1));
|
||||
return;
|
||||
}
|
||||
let data = '';
|
||||
res.on('data', function(chunk) { data += chunk; });
|
||||
res.on('end', function() {
|
||||
|
||||
675
.github/workflows/pocketbase-bot.yml
generated
vendored
675
.github/workflows/pocketbase-bot.yml
generated
vendored
@@ -1,675 +0,0 @@
|
||||
name: PocketBase Bot
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
pocketbase-bot:
|
||||
runs-on: self-hosted
|
||||
|
||||
# Only act on /pocketbase commands
|
||||
if: startsWith(github.event.comment.body, '/pocketbase')
|
||||
|
||||
steps:
|
||||
- name: Execute PocketBase bot command
|
||||
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 }}
|
||||
COMMENT_BODY: ${{ github.event.comment.body }}
|
||||
COMMENT_ID: ${{ github.event.comment.id }}
|
||||
ISSUE_NUMBER: ${{ github.event.issue.number }}
|
||||
REPO_OWNER: ${{ github.repository_owner }}
|
||||
REPO_NAME: ${{ github.event.repository.name }}
|
||||
ACTOR: ${{ github.event.comment.user.login }}
|
||||
ACTOR_ASSOCIATION: ${{ github.event.comment.author_association }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
node << 'ENDSCRIPT'
|
||||
(async function () {
|
||||
const https = require('https');
|
||||
const http = require('http');
|
||||
const url = require('url');
|
||||
|
||||
// ── HTTP helper with redirect following ────────────────────────────
|
||||
function request(fullUrl, opts, redirectCount) {
|
||||
redirectCount = redirectCount || 0;
|
||||
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) {
|
||||
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
||||
if (redirectCount >= 5) return reject(new Error('Too many redirects from ' + fullUrl));
|
||||
const redirectUrl = url.resolve(fullUrl, res.headers.location);
|
||||
res.resume();
|
||||
resolve(request(redirectUrl, opts, redirectCount + 1));
|
||||
return;
|
||||
}
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
// ── GitHub API helpers ─────────────────────────────────────────────
|
||||
const owner = process.env.REPO_OWNER;
|
||||
const repo = process.env.REPO_NAME;
|
||||
const issueNumber = parseInt(process.env.ISSUE_NUMBER, 10);
|
||||
const commentId = parseInt(process.env.COMMENT_ID, 10);
|
||||
const actor = process.env.ACTOR;
|
||||
|
||||
function ghRequest(path, method, body) {
|
||||
const headers = {
|
||||
'Authorization': 'Bearer ' + process.env.GITHUB_TOKEN,
|
||||
'Accept': 'application/vnd.github+json',
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
'User-Agent': 'PocketBase-Bot'
|
||||
};
|
||||
const bodyStr = body ? JSON.stringify(body) : undefined;
|
||||
if (bodyStr) headers['Content-Type'] = 'application/json';
|
||||
return request('https://api.github.com' + path, { method: method || 'GET', headers, body: bodyStr });
|
||||
}
|
||||
|
||||
async function addReaction(content) {
|
||||
try {
|
||||
await ghRequest(
|
||||
'/repos/' + owner + '/' + repo + '/issues/comments/' + commentId + '/reactions',
|
||||
'POST', { content }
|
||||
);
|
||||
} catch (e) {
|
||||
console.warn('Could not add reaction:', e.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function postComment(text) {
|
||||
const res = await ghRequest(
|
||||
'/repos/' + owner + '/' + repo + '/issues/' + issueNumber + '/comments',
|
||||
'POST', { body: text }
|
||||
);
|
||||
if (!res.ok) console.warn('Could not post comment:', res.body);
|
||||
}
|
||||
|
||||
// ── Permission check ───────────────────────────────────────────────
|
||||
// author_association: OWNER = repo/org owner, MEMBER = org member (includes Contributors team)
|
||||
const association = process.env.ACTOR_ASSOCIATION;
|
||||
if (association !== 'OWNER' && association !== 'MEMBER') {
|
||||
await addReaction('-1');
|
||||
await postComment(
|
||||
'❌ **PocketBase Bot**: @' + actor + ' is not authorized to use this command.\n' +
|
||||
'Only org members (Contributors team) can use `/pocketbase`.'
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// ── Acknowledge ────────────────────────────────────────────────────
|
||||
await addReaction('eyes');
|
||||
|
||||
// ── Parse command ──────────────────────────────────────────────────
|
||||
// Formats (first line of comment):
|
||||
// /pocketbase <slug> field=value [field=value ...] ← field updates (simple values)
|
||||
// /pocketbase <slug> set <field> ← value from code block below
|
||||
// /pocketbase <slug> note list|add|edit|remove ... ← note management
|
||||
// /pocketbase <slug> method list ← list install methods
|
||||
// /pocketbase <slug> method <type> cpu=N ram=N hdd=N ← edit install method resources
|
||||
const commentBody = process.env.COMMENT_BODY || '';
|
||||
const lines = commentBody.trim().split('\n');
|
||||
const firstLine = lines[0].trim();
|
||||
const withoutCmd = firstLine.replace(/^\/pocketbase\s+/, '').trim();
|
||||
|
||||
// Extract code block content from comment body (```...``` or ```lang\n...```)
|
||||
function extractCodeBlock(body) {
|
||||
const m = body.match(/```[^\n]*\n([\s\S]*?)```/);
|
||||
return m ? m[1].trim() : null;
|
||||
}
|
||||
const codeBlockValue = extractCodeBlock(commentBody);
|
||||
|
||||
const HELP_TEXT =
|
||||
'**Field update (simple):** `/pocketbase <slug> field=value [field=value ...]`\n\n' +
|
||||
'**Field update (HTML/multiline) — value from code block:**\n' +
|
||||
'````\n' +
|
||||
'/pocketbase <slug> set description\n' +
|
||||
'```html\n' +
|
||||
'<p>Your <b>HTML</b> or multi-line content here</p>\n' +
|
||||
'```\n' +
|
||||
'````\n\n' +
|
||||
'**Note management:**\n' +
|
||||
'```\n' +
|
||||
'/pocketbase <slug> note list\n' +
|
||||
'/pocketbase <slug> note add <type> "<text>"\n' +
|
||||
'/pocketbase <slug> note edit <type> "<old text>" "<new text>"\n' +
|
||||
'/pocketbase <slug> note remove <type> "<text>"\n' +
|
||||
'```\n\n' +
|
||||
'**Install method resources:**\n' +
|
||||
'```\n' +
|
||||
'/pocketbase <slug> method list\n' +
|
||||
'/pocketbase <slug> method <type> hdd=10\n' +
|
||||
'/pocketbase <slug> method <type> cpu=4 ram=2048 hdd=20\n' +
|
||||
'```\n\n' +
|
||||
'**Editable fields:** `name` `description` `logo` `documentation` `website` `project_url` `github` ' +
|
||||
'`config_path` `port` `default_user` `default_passwd` ' +
|
||||
'`updateable` `privileged` `has_arm` `is_dev` ' +
|
||||
'`is_disabled` `disable_message` `is_deleted` `deleted_message`';
|
||||
|
||||
if (!withoutCmd) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase Bot**: No slug or command specified.\n\n' + HELP_TEXT);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const spaceIdx = withoutCmd.indexOf(' ');
|
||||
const slug = (spaceIdx === -1 ? withoutCmd : withoutCmd.substring(0, spaceIdx)).trim();
|
||||
const rest = spaceIdx === -1 ? '' : withoutCmd.substring(spaceIdx + 1).trim();
|
||||
|
||||
if (!rest) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase Bot**: No command specified for slug `' + slug + '`.\n\n' + HELP_TEXT);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// ── Allowed fields and their types ─────────────────────────────────
|
||||
// ── PocketBase: authenticate (shared by all paths) ─────────────────
|
||||
const raw = process.env.POCKETBASE_URL.replace(/\/$/, '');
|
||||
const apiBase = /\/api$/i.test(raw) ? raw : raw + '/api';
|
||||
const coll = process.env.POCKETBASE_COLLECTION;
|
||||
|
||||
const authRes = await request(apiBase + '/collections/users/auth-with-password', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
identity: process.env.POCKETBASE_ADMIN_EMAIL,
|
||||
password: process.env.POCKETBASE_ADMIN_PASSWORD
|
||||
})
|
||||
});
|
||||
if (!authRes.ok) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase Bot**: PocketBase authentication failed. CC @' + owner + '/maintainers');
|
||||
process.exit(1);
|
||||
}
|
||||
const token = JSON.parse(authRes.body).token;
|
||||
|
||||
// ── PocketBase: find record by slug (shared by all paths) ──────────
|
||||
const recordsUrl = apiBase + '/collections/' + encodeURIComponent(coll) + '/records';
|
||||
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) {
|
||||
await addReaction('-1');
|
||||
await postComment(
|
||||
'❌ **PocketBase Bot**: No record found for slug `' + slug + '`.\n\n' +
|
||||
'Make sure the script was already pushed to PocketBase (JSON must exist and have been synced).'
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// ── Route: dispatch to subcommand handler ──────────────────────────
|
||||
const noteMatch = rest.match(/^note\s+(list|add|edit|remove)\b/i);
|
||||
const methodMatch = rest.match(/^method\b/i);
|
||||
const setMatch = rest.match(/^set\s+(\S+)/i);
|
||||
|
||||
if (noteMatch) {
|
||||
// ── NOTE SUBCOMMAND (reads/writes notes_json on script record) ────
|
||||
const noteAction = noteMatch[1].toLowerCase();
|
||||
const noteArgsStr = rest.substring(noteMatch[0].length).trim();
|
||||
|
||||
// Parse notes_json from the already-fetched script record
|
||||
// PocketBase may return JSON fields as already-parsed objects
|
||||
let notesArr = [];
|
||||
try {
|
||||
const rawNotes = record.notes_json;
|
||||
notesArr = Array.isArray(rawNotes) ? rawNotes : JSON.parse(rawNotes || '[]');
|
||||
} catch (e) { notesArr = []; }
|
||||
|
||||
// Token parser: unquoted-word OR "quoted string" (supports \" escapes)
|
||||
function parseNoteTokens(str) {
|
||||
const tokens = [];
|
||||
let pos = 0;
|
||||
while (pos < str.length) {
|
||||
while (pos < str.length && /\s/.test(str[pos])) pos++;
|
||||
if (pos >= str.length) break;
|
||||
if (str[pos] === '"') {
|
||||
pos++;
|
||||
let start = pos;
|
||||
while (pos < str.length && str[pos] !== '"') {
|
||||
if (str[pos] === '\\') pos++;
|
||||
pos++;
|
||||
}
|
||||
tokens.push(str.substring(start, pos).replace(/\\"/g, '"'));
|
||||
if (pos < str.length) pos++;
|
||||
} else {
|
||||
let start = pos;
|
||||
while (pos < str.length && !/\s/.test(str[pos])) pos++;
|
||||
tokens.push(str.substring(start, pos));
|
||||
}
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
function formatNotesList(arr) {
|
||||
if (arr.length === 0) return '*None*';
|
||||
return arr.map(function (n, i) {
|
||||
return (i + 1) + '. **`' + (n.type || '?') + '`**: ' + (n.text || '');
|
||||
}).join('\n');
|
||||
}
|
||||
|
||||
async function patchNotesJson(arr) {
|
||||
const res = await request(recordsUrl + '/' + record.id, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ notes_json: JSON.stringify(arr) })
|
||||
});
|
||||
if (!res.ok) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase Bot**: Failed to update `notes_json`:\n```\n' + res.body + '\n```');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (noteAction === 'list') {
|
||||
await addReaction('+1');
|
||||
await postComment(
|
||||
'ℹ️ **PocketBase Bot**: Notes for **`' + slug + '`** (' + notesArr.length + ' total)\n\n' +
|
||||
formatNotesList(notesArr)
|
||||
);
|
||||
|
||||
} else if (noteAction === 'add') {
|
||||
const tokens = parseNoteTokens(noteArgsStr);
|
||||
if (tokens.length < 2) {
|
||||
await addReaction('-1');
|
||||
await postComment(
|
||||
'❌ **PocketBase Bot**: `note add` requires `<type>` and `"<text>"`.\n\n' +
|
||||
'**Usage:** `/pocketbase ' + slug + ' note add <type> "<text>"`'
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
const noteType = tokens[0].toLowerCase();
|
||||
const noteText = tokens.slice(1).join(' ');
|
||||
notesArr.push({ type: noteType, text: noteText });
|
||||
await patchNotesJson(notesArr);
|
||||
await addReaction('+1');
|
||||
await postComment(
|
||||
'✅ **PocketBase Bot**: Added note to **`' + slug + '`**\n\n' +
|
||||
'- **Type:** `' + noteType + '`\n' +
|
||||
'- **Text:** ' + noteText + '\n\n' +
|
||||
'*Executed by @' + actor + '*'
|
||||
);
|
||||
|
||||
} else if (noteAction === 'edit') {
|
||||
const tokens = parseNoteTokens(noteArgsStr);
|
||||
if (tokens.length < 3) {
|
||||
await addReaction('-1');
|
||||
await postComment(
|
||||
'❌ **PocketBase Bot**: `note edit` requires `<type>`, `"<old text>"`, and `"<new text>"`.\n\n' +
|
||||
'**Usage:** `/pocketbase ' + slug + ' note edit <type> "<old text>" "<new text>"`\n\n' +
|
||||
'Use `/pocketbase ' + slug + ' note list` to see current notes.'
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
const noteType = tokens[0].toLowerCase();
|
||||
const oldText = tokens[1];
|
||||
const newText = tokens[2];
|
||||
const idx = notesArr.findIndex(function (n) {
|
||||
return n.type.toLowerCase() === noteType && n.text === oldText;
|
||||
});
|
||||
if (idx === -1) {
|
||||
await addReaction('-1');
|
||||
await postComment(
|
||||
'❌ **PocketBase Bot**: No `' + noteType + '` note found with that exact text.\n\n' +
|
||||
'**Current notes for `' + slug + '`:**\n' + formatNotesList(notesArr)
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
notesArr[idx].text = newText;
|
||||
await patchNotesJson(notesArr);
|
||||
await addReaction('+1');
|
||||
await postComment(
|
||||
'✅ **PocketBase Bot**: Edited note in **`' + slug + '`**\n\n' +
|
||||
'- **Type:** `' + noteType + '`\n' +
|
||||
'- **Old:** ' + oldText + '\n' +
|
||||
'- **New:** ' + newText + '\n\n' +
|
||||
'*Executed by @' + actor + '*'
|
||||
);
|
||||
|
||||
} else if (noteAction === 'remove') {
|
||||
const tokens = parseNoteTokens(noteArgsStr);
|
||||
if (tokens.length < 2) {
|
||||
await addReaction('-1');
|
||||
await postComment(
|
||||
'❌ **PocketBase Bot**: `note remove` requires `<type>` and `"<text>"`.\n\n' +
|
||||
'**Usage:** `/pocketbase ' + slug + ' note remove <type> "<text>"`\n\n' +
|
||||
'Use `/pocketbase ' + slug + ' note list` to see current notes.'
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
const noteType = tokens[0].toLowerCase();
|
||||
const noteText = tokens[1];
|
||||
const before = notesArr.length;
|
||||
notesArr = notesArr.filter(function (n) {
|
||||
return !(n.type.toLowerCase() === noteType && n.text === noteText);
|
||||
});
|
||||
if (notesArr.length === before) {
|
||||
await addReaction('-1');
|
||||
await postComment(
|
||||
'❌ **PocketBase Bot**: No `' + noteType + '` note found with that exact text.\n\n' +
|
||||
'**Current notes for `' + slug + '`:**\n' + formatNotesList(notesArr)
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
await patchNotesJson(notesArr);
|
||||
await addReaction('+1');
|
||||
await postComment(
|
||||
'✅ **PocketBase Bot**: Removed note from **`' + slug + '`**\n\n' +
|
||||
'- **Type:** `' + noteType + '`\n' +
|
||||
'- **Text:** ' + noteText + '\n\n' +
|
||||
'*Executed by @' + actor + '*'
|
||||
);
|
||||
}
|
||||
|
||||
} else if (methodMatch) {
|
||||
// ── METHOD SUBCOMMAND (reads/writes install_methods_json on script record) ──
|
||||
const methodArgs = rest.replace(/^method\s*/i, '').trim();
|
||||
const methodListMode = !methodArgs || methodArgs.toLowerCase() === 'list';
|
||||
|
||||
// Parse install_methods_json from the already-fetched script record
|
||||
// PocketBase may return JSON fields as already-parsed objects
|
||||
let methodsArr = [];
|
||||
try {
|
||||
const rawMethods = record.install_methods_json;
|
||||
methodsArr = Array.isArray(rawMethods) ? rawMethods : JSON.parse(rawMethods || '[]');
|
||||
} catch (e) { methodsArr = []; }
|
||||
|
||||
function formatMethodsList(arr) {
|
||||
if (arr.length === 0) return '*None*';
|
||||
return arr.map(function (im, i) {
|
||||
const r = im.resources || {};
|
||||
return (i + 1) + '. **`' + (im.type || '?') + '`** — CPU: `' + (r.cpu != null ? r.cpu : '?') +
|
||||
'` · RAM: `' + (r.ram != null ? r.ram : '?') + ' MB` · HDD: `' + (r.hdd != null ? r.hdd : '?') + ' GB`';
|
||||
}).join('\n');
|
||||
}
|
||||
|
||||
async function patchInstallMethodsJson(arr) {
|
||||
const res = await request(recordsUrl + '/' + record.id, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ install_methods_json: JSON.stringify(arr) })
|
||||
});
|
||||
if (!res.ok) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase Bot**: Failed to update `install_methods_json`:\n```\n' + res.body + '\n```');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (methodListMode) {
|
||||
await addReaction('+1');
|
||||
await postComment(
|
||||
'ℹ️ **PocketBase Bot**: Install methods for **`' + slug + '`** (' + methodsArr.length + ' total)\n\n' +
|
||||
formatMethodsList(methodsArr)
|
||||
);
|
||||
} else {
|
||||
// Parse: <type> cpu=N ram=N hdd=N
|
||||
const methodParts = methodArgs.match(/^(\S+)\s+(.+)$/);
|
||||
if (!methodParts) {
|
||||
await addReaction('-1');
|
||||
await postComment(
|
||||
'❌ **PocketBase Bot**: Invalid `method` syntax.\n\n' +
|
||||
'**Usage:**\n```\n/pocketbase ' + slug + ' method list\n/pocketbase ' + slug + ' method <type> hdd=10\n/pocketbase ' + slug + ' method <type> cpu=4 ram=2048 hdd=20\n```'
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
const targetType = methodParts[1].toLowerCase();
|
||||
const resourcesStr = methodParts[2];
|
||||
|
||||
// Parse resource fields (only cpu/ram/hdd allowed)
|
||||
const RESOURCE_FIELDS = { cpu: true, ram: true, hdd: true };
|
||||
const resourceChanges = {};
|
||||
const rePairs = /([a-z]+)=(\d+)/gi;
|
||||
let m;
|
||||
while ((m = rePairs.exec(resourcesStr)) !== null) {
|
||||
const key = m[1].toLowerCase();
|
||||
if (RESOURCE_FIELDS[key]) resourceChanges[key] = parseInt(m[2], 10);
|
||||
}
|
||||
if (Object.keys(resourceChanges).length === 0) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase Bot**: No valid resource fields found. Use `cpu=N`, `ram=N`, `hdd=N`.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Find matching method by type name (case-insensitive)
|
||||
const idx = methodsArr.findIndex(function (im) {
|
||||
return (im.type || '').toLowerCase() === targetType;
|
||||
});
|
||||
if (idx === -1) {
|
||||
await addReaction('-1');
|
||||
const availableTypes = methodsArr.map(function (im) { return im.type || '?'; });
|
||||
await postComment(
|
||||
'❌ **PocketBase Bot**: No install method with type `' + targetType + '` found for `' + slug + '`.\n\n' +
|
||||
'**Available types:** `' + (availableTypes.length ? availableTypes.join('`, `') : '(none)') + '`\n\n' +
|
||||
'Use `/pocketbase ' + slug + ' method list` to see all methods.'
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!methodsArr[idx].resources) methodsArr[idx].resources = {};
|
||||
if (resourceChanges.cpu != null) methodsArr[idx].resources.cpu = resourceChanges.cpu;
|
||||
if (resourceChanges.ram != null) methodsArr[idx].resources.ram = resourceChanges.ram;
|
||||
if (resourceChanges.hdd != null) methodsArr[idx].resources.hdd = resourceChanges.hdd;
|
||||
|
||||
await patchInstallMethodsJson(methodsArr);
|
||||
|
||||
const changesLines = Object.entries(resourceChanges)
|
||||
.map(function ([k, v]) { return '- `' + k + '` → `' + v + (k === 'ram' ? ' MB' : k === 'hdd' ? ' GB' : '') + '`'; })
|
||||
.join('\n');
|
||||
await addReaction('+1');
|
||||
await postComment(
|
||||
'✅ **PocketBase Bot**: Updated install method **`' + methodsArr[idx].type + '`** for **`' + slug + '`**\n\n' +
|
||||
'**Changes applied:**\n' + changesLines + '\n\n' +
|
||||
'*Executed by @' + actor + '*'
|
||||
);
|
||||
}
|
||||
|
||||
} else if (setMatch) {
|
||||
// ── SET SUBCOMMAND (multi-line / HTML / special chars via code block) ──
|
||||
const fieldName = setMatch[1].toLowerCase();
|
||||
const SET_ALLOWED = {
|
||||
name: 'string', description: 'string', logo: 'string',
|
||||
documentation: 'string', website: 'string', project_url: 'string', github: 'string',
|
||||
config_path: 'string', disable_message: 'string', deleted_message: 'string'
|
||||
};
|
||||
if (!SET_ALLOWED[fieldName]) {
|
||||
await addReaction('-1');
|
||||
await postComment(
|
||||
'❌ **PocketBase Bot**: `set` only supports text fields.\n\n' +
|
||||
'**Allowed:** `' + Object.keys(SET_ALLOWED).join('`, `') + '`\n\n' +
|
||||
'For boolean/number fields use `field=value` syntax instead.'
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
if (!codeBlockValue) {
|
||||
await addReaction('-1');
|
||||
await postComment(
|
||||
'❌ **PocketBase Bot**: `set` requires a code block with the value.\n\n' +
|
||||
'**Usage:**\n````\n/pocketbase ' + slug + ' set ' + fieldName + '\n```\nYour content here (HTML, multiline, special chars all fine)\n```\n````'
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
const setPayload = {};
|
||||
setPayload[fieldName] = codeBlockValue;
|
||||
const setPatchRes = await request(recordsUrl + '/' + record.id, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(setPayload)
|
||||
});
|
||||
if (!setPatchRes.ok) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase Bot**: PATCH failed for `' + slug + '`:\n```\n' + setPatchRes.body + '\n```');
|
||||
process.exit(1);
|
||||
}
|
||||
const preview = codeBlockValue.length > 300 ? codeBlockValue.substring(0, 300) + '…' : codeBlockValue;
|
||||
await addReaction('+1');
|
||||
await postComment(
|
||||
'✅ **PocketBase Bot**: Set `' + fieldName + '` for **`' + slug + '`**\n\n' +
|
||||
'**Value set:**\n```\n' + preview + '\n```\n\n' +
|
||||
'*Executed by @' + actor + '*'
|
||||
);
|
||||
|
||||
} else {
|
||||
// ── FIELD=VALUE PATH ─────────────────────────────────────────────
|
||||
const fieldsStr = rest;
|
||||
|
||||
// Skipped: slug, script_created/updated, created (auto), categories/
|
||||
// install_methods/notes/type (relations), github_data/install_methods_json/
|
||||
// notes_json (auto-generated), execute_in (select relation), last_update_commit (auto)
|
||||
const ALLOWED_FIELDS = {
|
||||
name: 'string',
|
||||
description: 'string',
|
||||
logo: 'string',
|
||||
documentation: 'string',
|
||||
website: 'string',
|
||||
project_url: 'string',
|
||||
github: 'string',
|
||||
config_path: 'string',
|
||||
port: 'number',
|
||||
default_user: 'nullable_string',
|
||||
default_passwd: 'nullable_string',
|
||||
updateable: 'boolean',
|
||||
privileged: 'boolean',
|
||||
has_arm: 'boolean',
|
||||
is_dev: 'boolean',
|
||||
is_disabled: 'boolean',
|
||||
disable_message: 'string',
|
||||
is_deleted: 'boolean',
|
||||
deleted_message: 'string',
|
||||
};
|
||||
|
||||
// Field=value parser (handles quoted values and empty=null)
|
||||
function parseFields(str) {
|
||||
const fields = {};
|
||||
let pos = 0;
|
||||
while (pos < str.length) {
|
||||
while (pos < str.length && /\s/.test(str[pos])) pos++;
|
||||
if (pos >= str.length) break;
|
||||
let keyStart = pos;
|
||||
while (pos < str.length && str[pos] !== '=' && !/\s/.test(str[pos])) pos++;
|
||||
const key = str.substring(keyStart, pos).trim();
|
||||
if (!key || pos >= str.length || str[pos] !== '=') { pos++; continue; }
|
||||
pos++;
|
||||
let value;
|
||||
if (str[pos] === '"') {
|
||||
pos++;
|
||||
let valStart = pos;
|
||||
while (pos < str.length && str[pos] !== '"') {
|
||||
if (str[pos] === '\\') pos++;
|
||||
pos++;
|
||||
}
|
||||
value = str.substring(valStart, pos).replace(/\\"/g, '"');
|
||||
if (pos < str.length) pos++;
|
||||
} else {
|
||||
let valStart = pos;
|
||||
while (pos < str.length && !/\s/.test(str[pos])) pos++;
|
||||
value = str.substring(valStart, pos);
|
||||
}
|
||||
fields[key] = value;
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
const parsedFields = parseFields(fieldsStr);
|
||||
|
||||
const unknownFields = Object.keys(parsedFields).filter(function (f) { return !ALLOWED_FIELDS[f]; });
|
||||
if (unknownFields.length > 0) {
|
||||
await addReaction('-1');
|
||||
await postComment(
|
||||
'❌ **PocketBase Bot**: Unknown field(s): `' + unknownFields.join('`, `') + '`\n\n' +
|
||||
'**Allowed fields:** `' + Object.keys(ALLOWED_FIELDS).join('`, `') + '`'
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (Object.keys(parsedFields).length === 0) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase Bot**: Could not parse any valid `field=value` pairs.\n\n' + HELP_TEXT);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Cast values to correct types
|
||||
const payload = {};
|
||||
for (const [key, rawVal] of Object.entries(parsedFields)) {
|
||||
const type = ALLOWED_FIELDS[key];
|
||||
if (type === 'boolean') {
|
||||
if (rawVal === 'true') payload[key] = true;
|
||||
else if (rawVal === 'false') payload[key] = false;
|
||||
else {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase Bot**: `' + key + '` must be `true` or `false`, got: `' + rawVal + '`');
|
||||
process.exit(0);
|
||||
}
|
||||
} else if (type === 'number') {
|
||||
const n = parseInt(rawVal, 10);
|
||||
if (isNaN(n)) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase Bot**: `' + key + '` must be a number, got: `' + rawVal + '`');
|
||||
process.exit(0);
|
||||
}
|
||||
payload[key] = n;
|
||||
} else if (type === 'nullable_string') {
|
||||
payload[key] = rawVal === '' ? null : rawVal;
|
||||
} else {
|
||||
payload[key] = rawVal;
|
||||
}
|
||||
}
|
||||
|
||||
const patchRes = await request(recordsUrl + '/' + record.id, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
if (!patchRes.ok) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase Bot**: PATCH failed for `' + slug + '`:\n```\n' + patchRes.body + '\n```');
|
||||
process.exit(1);
|
||||
}
|
||||
await addReaction('+1');
|
||||
const changesLines = Object.entries(payload)
|
||||
.map(function ([k, v]) { return '- `' + k + '` → `' + JSON.stringify(v) + '`'; })
|
||||
.join('\n');
|
||||
await postComment(
|
||||
'✅ **PocketBase Bot**: Updated **`' + slug + '`** successfully!\n\n' +
|
||||
'**Changes applied:**\n' + changesLines + '\n\n' +
|
||||
'*Executed by @' + actor + '*'
|
||||
);
|
||||
}
|
||||
|
||||
console.log('Done.');
|
||||
})().catch(function (e) {
|
||||
console.error('Fatal error:', e.message || e);
|
||||
process.exit(1);
|
||||
});
|
||||
ENDSCRIPT
|
||||
shell: bash
|
||||
24
.github/workflows/push-json-to-pocketbase.yml
generated
vendored
24
.github/workflows/push-json-to-pocketbase.yml
generated
vendored
@@ -48,8 +48,7 @@ jobs:
|
||||
const https = require('https');
|
||||
const http = require('http');
|
||||
const url = require('url');
|
||||
function request(fullUrl, opts, redirectCount) {
|
||||
redirectCount = redirectCount || 0;
|
||||
function request(fullUrl, opts) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
const u = url.parse(fullUrl);
|
||||
const isHttps = u.protocol === 'https:';
|
||||
@@ -64,13 +63,6 @@ jobs:
|
||||
if (body) options.headers['Content-Length'] = Buffer.byteLength(body);
|
||||
const lib = isHttps ? https : http;
|
||||
const req = lib.request(options, function(res) {
|
||||
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
||||
if (redirectCount >= 5) return reject(new Error('Too many redirects from ' + fullUrl));
|
||||
const redirectUrl = url.resolve(fullUrl, res.headers.location);
|
||||
res.resume();
|
||||
resolve(request(redirectUrl, opts, redirectCount + 1));
|
||||
return;
|
||||
}
|
||||
let data = '';
|
||||
res.on('data', function(chunk) { data += chunk; });
|
||||
res.on('end', function() {
|
||||
@@ -133,15 +125,15 @@ jobs:
|
||||
var osVersionToId = {};
|
||||
try {
|
||||
const res = await request(apiBase + '/collections/z_ref_note_types/records?perPage=500', { headers: { 'Authorization': token } });
|
||||
if (res.ok) JSON.parse(res.body).items?.forEach(function(item) { if (item.type != null) { noteTypeToId[item.type] = item.id; noteTypeToId[item.type.toLowerCase()] = item.id; } });
|
||||
if (res.ok) JSON.parse(res.body).items?.forEach(function(item) { if (item.type != null) noteTypeToId[item.type] = item.id; });
|
||||
} catch (e) { console.warn('z_ref_note_types:', e.message); }
|
||||
try {
|
||||
const res = await request(apiBase + '/collections/z_ref_install_method_types/records?perPage=500', { headers: { 'Authorization': token } });
|
||||
if (res.ok) JSON.parse(res.body).items?.forEach(function(item) { if (item.type != null) { installMethodTypeToId[item.type] = item.id; installMethodTypeToId[item.type.toLowerCase()] = item.id; } });
|
||||
if (res.ok) JSON.parse(res.body).items?.forEach(function(item) { if (item.type != null) installMethodTypeToId[item.type] = item.id; });
|
||||
} catch (e) { console.warn('z_ref_install_method_types:', e.message); }
|
||||
try {
|
||||
const res = await request(apiBase + '/collections/z_ref_os/records?perPage=500', { headers: { 'Authorization': token } });
|
||||
if (res.ok) JSON.parse(res.body).items?.forEach(function(item) { if (item.os != null) { osToId[item.os] = item.id; osToId[item.os.toLowerCase()] = item.id; } });
|
||||
if (res.ok) JSON.parse(res.body).items?.forEach(function(item) { if (item.os != null) osToId[item.os] = item.id; });
|
||||
} catch (e) { console.warn('z_ref_os:', e.message); }
|
||||
try {
|
||||
const res = await request(apiBase + '/collections/z_ref_os_version/records?perPage=500&expand=os', { headers: { 'Authorization': token } });
|
||||
@@ -162,7 +154,7 @@ jobs:
|
||||
name: data.name,
|
||||
slug: data.slug,
|
||||
script_created: data.date_created || data.script_created,
|
||||
script_updated: new Date().toISOString().split('T')[0],
|
||||
script_updated: data.date_created || data.script_updated,
|
||||
updateable: data.updateable,
|
||||
privileged: data.privileged,
|
||||
port: data.interface_port != null ? data.interface_port : data.port,
|
||||
@@ -171,8 +163,8 @@ jobs:
|
||||
logo: data.logo,
|
||||
description: data.description,
|
||||
config_path: data.config_path,
|
||||
default_user: (data.default_credentials && data.default_credentials.username) || data.default_user || null,
|
||||
default_passwd: (data.default_credentials && data.default_credentials.password) || data.default_passwd || null,
|
||||
default_user: (data.default_credentials && data.default_credentials.username) || data.default_user,
|
||||
default_passwd: (data.default_credentials && data.default_credentials.password) || data.default_passwd,
|
||||
is_dev: false
|
||||
};
|
||||
var resolvedType = typeValueToId[data.type];
|
||||
@@ -198,7 +190,7 @@ jobs:
|
||||
var postRes = await request(notesCollUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ text: note.text || '', type: typeId, script: scriptId })
|
||||
body: JSON.stringify({ text: note.text || '', type: typeId })
|
||||
});
|
||||
if (postRes.ok) noteIds.push(JSON.parse(postRes.body).id);
|
||||
}
|
||||
|
||||
12
.github/workflows/update-script-timestamp-on-sh-change.yml
generated
vendored
12
.github/workflows/update-script-timestamp-on-sh-change.yml
generated
vendored
@@ -83,8 +83,7 @@ jobs:
|
||||
const http = require('http');
|
||||
const url = require('url');
|
||||
|
||||
function request(fullUrl, opts, redirectCount) {
|
||||
redirectCount = redirectCount || 0;
|
||||
function request(fullUrl, opts) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
const u = url.parse(fullUrl);
|
||||
const isHttps = u.protocol === 'https:';
|
||||
@@ -99,13 +98,6 @@ jobs:
|
||||
if (body) options.headers['Content-Length'] = Buffer.byteLength(body);
|
||||
const lib = isHttps ? https : http;
|
||||
const req = lib.request(options, function(res) {
|
||||
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
||||
if (redirectCount >= 5) return reject(new Error('Too many redirects from ' + fullUrl));
|
||||
const redirectUrl = url.resolve(fullUrl, res.headers.location);
|
||||
res.resume();
|
||||
resolve(request(redirectUrl, opts, redirectCount + 1));
|
||||
return;
|
||||
}
|
||||
let data = '';
|
||||
res.on('data', function(chunk) { data += chunk; });
|
||||
res.on('end', function() {
|
||||
@@ -159,7 +151,7 @@ jobs:
|
||||
method: 'PATCH',
|
||||
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
script_updated: new Date().toISOString().split('T')[0],
|
||||
name: record.name || record.slug,
|
||||
last_update_commit: process.env.PR_URL || process.env.COMMIT_URL || ''
|
||||
})
|
||||
});
|
||||
|
||||
396
CHANGELOG.md
396
CHANGELOG.md
@@ -26,9 +26,6 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<details>
|
||||
<summary><h2>📜 History</h2></summary>
|
||||
@@ -39,7 +36,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
||||
|
||||
|
||||
<details>
|
||||
<summary><h4>March (14 entries)</h4></summary>
|
||||
<summary><h4>March (7 entries)</h4></summary>
|
||||
|
||||
[View March 2026 Changelog](.github/changelogs/2026/03.md)
|
||||
|
||||
@@ -423,163 +420,6 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
||||
|
||||
</details>
|
||||
|
||||
## 2026-03-19
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- Owncast: increase default disk size from 2GB to 10GB [@Copilot](https://github.com/Copilot) ([#13079](https://github.com/community-scripts/ProxmoxVE/pull/13079))
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Increase Tracearr RAM; derive APP_VERSION [@MickLesk](https://github.com/MickLesk) ([#13087](https://github.com/community-scripts/ProxmoxVE/pull/13087))
|
||||
- ProjectSend: Update application access URL [@tremor021](https://github.com/tremor021) ([#13078](https://github.com/community-scripts/ProxmoxVE/pull/13078))
|
||||
- Dispatcharr: use npm install --no-audit --progress=false [@MickLesk](https://github.com/MickLesk) ([#13074](https://github.com/community-scripts/ProxmoxVE/pull/13074))
|
||||
- core: reorder hwaccel setup and adjust GPU group usermod [@MickLesk](https://github.com/MickLesk) ([#13072](https://github.com/community-scripts/ProxmoxVE/pull/13072))
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- github: add PocketBase bot workflow [@MickLesk](https://github.com/MickLesk) ([#13075](https://github.com/community-scripts/ProxmoxVE/pull/13075))
|
||||
|
||||
## 2026-03-18
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- Alpine-Ntfy [@MickLesk](https://github.com/MickLesk) ([#13048](https://github.com/community-scripts/ProxmoxVE/pull/13048))
|
||||
- Split-Pro ([#12975](https://github.com/community-scripts/ProxmoxVE/pull/12975))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Tdarr: use curl_with_retry and correct exit code [@MickLesk](https://github.com/MickLesk) ([#13060](https://github.com/community-scripts/ProxmoxVE/pull/13060))
|
||||
- reitti: fix: v4 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#13039](https://github.com/community-scripts/ProxmoxVE/pull/13039))
|
||||
- Paperless-NGX: increase default RAM to 3GB [@MickLesk](https://github.com/MickLesk) ([#13018](https://github.com/community-scripts/ProxmoxVE/pull/13018))
|
||||
- Plex: restart service after update to apply new version [@MickLesk](https://github.com/MickLesk) ([#13017](https://github.com/community-scripts/ProxmoxVE/pull/13017))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- tools: centralize GPU group setup via setup_hwaccel [@MickLesk](https://github.com/MickLesk) ([#13044](https://github.com/community-scripts/ProxmoxVE/pull/13044))
|
||||
- Termix: add guacd build and systemd integration [@MickLesk](https://github.com/MickLesk) ([#12999](https://github.com/community-scripts/ProxmoxVE/pull/12999))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Podman: replace deprecated commands with Quadlets [@MickLesk](https://github.com/MickLesk) ([#13052](https://github.com/community-scripts/ProxmoxVE/pull/13052))
|
||||
- Refactor: Jellyfin repo, ffmpeg package and symlinks [@MickLesk](https://github.com/MickLesk) ([#13045](https://github.com/community-scripts/ProxmoxVE/pull/13045))
|
||||
- pve-scripts-local: Increase default disk size from 4GB to 10GB [@MickLesk](https://github.com/MickLesk) ([#13009](https://github.com/community-scripts/ProxmoxVE/pull/13009))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- tools.func Implement pg_cron setup for setup_postgresql [@MickLesk](https://github.com/MickLesk) ([#13053](https://github.com/community-scripts/ProxmoxVE/pull/13053))
|
||||
- tools.func: Implement check_for_gh_tag function [@MickLesk](https://github.com/MickLesk) ([#12998](https://github.com/community-scripts/ProxmoxVE/pull/12998))
|
||||
- tools.func: Implement fetch_and_deploy_gh_tag function [@MickLesk](https://github.com/MickLesk) ([#13000](https://github.com/community-scripts/ProxmoxVE/pull/13000))
|
||||
|
||||
## 2026-03-17
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Gluetun: add OpenVPN process user and cleanup stale config [@MickLesk](https://github.com/MickLesk) ([#13016](https://github.com/community-scripts/ProxmoxVE/pull/13016))
|
||||
- Frigate: check OpenVino model files exist before configuring detector and use curl_with_retry instead of default wget [@MickLesk](https://github.com/MickLesk) ([#13019](https://github.com/community-scripts/ProxmoxVE/pull/13019))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- tools.func: Update `create_self_signed_cert()` [@tremor021](https://github.com/tremor021) ([#13008](https://github.com/community-scripts/ProxmoxVE/pull/13008))
|
||||
|
||||
## 2026-03-16
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- Gluetun ([#12976](https://github.com/community-scripts/ProxmoxVE/pull/12976))
|
||||
- Anytype-Server ([#12974](https://github.com/community-scripts/ProxmoxVE/pull/12974))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Immich: use gcc-13 for compilation & add uv python pre-install with retry logic [@MickLesk](https://github.com/MickLesk) ([#12935](https://github.com/community-scripts/ProxmoxVE/pull/12935))
|
||||
- Tautulli: add setuptools<81 constraint to update script [@MickLesk](https://github.com/MickLesk) ([#12959](https://github.com/community-scripts/ProxmoxVE/pull/12959))
|
||||
- Seerr: add missing build deps [@MickLesk](https://github.com/MickLesk) ([#12960](https://github.com/community-scripts/ProxmoxVE/pull/12960))
|
||||
- fix: yubal update [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12961](https://github.com/community-scripts/ProxmoxVE/pull/12961))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- hwaccel: remove ROCm install from AMD APU setup [@MickLesk](https://github.com/MickLesk) ([#12958](https://github.com/community-scripts/ProxmoxVE/pull/12958))
|
||||
|
||||
## 2026-03-15
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- Yamtrack ([#12936](https://github.com/community-scripts/ProxmoxVE/pull/12936))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Wishlist: use --frozen-lockfile for pnpm install [@MickLesk](https://github.com/MickLesk) ([#12892](https://github.com/community-scripts/ProxmoxVE/pull/12892))
|
||||
- SparkyFitness: use --legacy-peer-deps for npm install [@MickLesk](https://github.com/MickLesk) ([#12888](https://github.com/community-scripts/ProxmoxVE/pull/12888))
|
||||
- Frigate: add fallback for OpenVino labelmap file [@MickLesk](https://github.com/MickLesk) ([#12889](https://github.com/community-scripts/ProxmoxVE/pull/12889))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Refactor: ITSM-NG [@MickLesk](https://github.com/MickLesk) ([#12918](https://github.com/community-scripts/ProxmoxVE/pull/12918))
|
||||
- core: unify RELEASE variable for check_for_gh_release and fetch_and_deploy [@MickLesk](https://github.com/MickLesk) ([#12917](https://github.com/community-scripts/ProxmoxVE/pull/12917))
|
||||
- Standardize NSAPP names across VM scripts [@MickLesk](https://github.com/MickLesk) ([#12924](https://github.com/community-scripts/ProxmoxVE/pull/12924))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- core: retry downloads with exponential backoff [@MickLesk](https://github.com/MickLesk) ([#12896](https://github.com/community-scripts/ProxmoxVE/pull/12896))
|
||||
|
||||
### ❔ Uncategorized
|
||||
|
||||
- [go2rtc] Add ffmpeg dependency to install script [@Copilot](https://github.com/Copilot) ([#12944](https://github.com/community-scripts/ProxmoxVE/pull/12944))
|
||||
|
||||
## 2026-03-14
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Patchmon: remove v prefix from pinned version [@MickLesk](https://github.com/MickLesk) ([#12891](https://github.com/community-scripts/ProxmoxVE/pull/12891))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- tools.func: don't abort on AMD repo apt update failure [@MickLesk](https://github.com/MickLesk) ([#12890](https://github.com/community-scripts/ProxmoxVE/pull/12890))
|
||||
|
||||
## 2026-03-13
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Hotfix: Removed clean install usage from original script. [@nickheyer](https://github.com/nickheyer) ([#12870](https://github.com/community-scripts/ProxmoxVE/pull/12870))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Discopanel: V2 Support + Script rewrite [@nickheyer](https://github.com/nickheyer) ([#12763](https://github.com/community-scripts/ProxmoxVE/pull/12763))
|
||||
|
||||
### 🧰 Tools
|
||||
|
||||
- update-apps: fix restore path, add PBS support and improve restore messages [@omertahaoztop](https://github.com/omertahaoztop) ([#12528](https://github.com/community-scripts/ProxmoxVE/pull/12528))
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- fix(pve-privilege-converter): handle already stopped container in manage_states [@liuqitoday](https://github.com/liuqitoday) ([#12765](https://github.com/community-scripts/ProxmoxVE/pull/12765))
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Update: Docs/website metadata workflow [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#12858](https://github.com/community-scripts/ProxmoxVE/pull/12858))
|
||||
|
||||
## 2026-03-12
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
@@ -1379,4 +1219,236 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
||||
|
||||
- #### 📝 Script Information
|
||||
|
||||
- SQLServer-2025: add PVE9/Kernel 6.x incompatibility warning [@MickLesk](https://github.com/MickLesk) ([#11829](https://github.com/community-scripts/ProxmoxVE/pull/11829))
|
||||
- SQLServer-2025: add PVE9/Kernel 6.x incompatibility warning [@MickLesk](https://github.com/MickLesk) ([#11829](https://github.com/community-scripts/ProxmoxVE/pull/11829))
|
||||
|
||||
## 2026-02-12
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- EMQX: increase disk to 6GB and add optional MQ disable prompt [@MickLesk](https://github.com/MickLesk) ([#11844](https://github.com/community-scripts/ProxmoxVE/pull/11844))
|
||||
- Increased the Grafana container default disk size. [@shtefko](https://github.com/shtefko) ([#11840](https://github.com/community-scripts/ProxmoxVE/pull/11840))
|
||||
- Pangolin: Update database generation command in install script [@tremor021](https://github.com/tremor021) ([#11825](https://github.com/community-scripts/ProxmoxVE/pull/11825))
|
||||
- Deluge: add python3-setuptools as dep [@MickLesk](https://github.com/MickLesk) ([#11833](https://github.com/community-scripts/ProxmoxVE/pull/11833))
|
||||
- Dispatcharr: migrate to uv sync [@MickLesk](https://github.com/MickLesk) ([#11831](https://github.com/community-scripts/ProxmoxVE/pull/11831))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- Archlinux-VM: fix LVM/LVM-thin storage and improve error reporting | VM's add correct exit_code for analytics [@MickLesk](https://github.com/MickLesk) ([#11842](https://github.com/community-scripts/ProxmoxVE/pull/11842))
|
||||
- Debian13-VM: Optimize First Boot & add noCloud/Cloud Selection [@MickLesk](https://github.com/MickLesk) ([#11810](https://github.com/community-scripts/ProxmoxVE/pull/11810))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- tools.func: auto-detect binary vs armored GPG keys in setup_deb822_repo [@MickLesk](https://github.com/MickLesk) ([#11841](https://github.com/community-scripts/ProxmoxVE/pull/11841))
|
||||
- core: remove old Go API and extend misc/api.func with new backend [@MickLesk](https://github.com/MickLesk) ([#11822](https://github.com/community-scripts/ProxmoxVE/pull/11822))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- error_handler: prevent stuck 'installing' status [@MickLesk](https://github.com/MickLesk) ([#11845](https://github.com/community-scripts/ProxmoxVE/pull/11845))
|
||||
|
||||
### 🧰 Tools
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Tailscale: fix DNS check and keyrings directory issues [@MickLesk](https://github.com/MickLesk) ([#11837](https://github.com/community-scripts/ProxmoxVE/pull/11837))
|
||||
|
||||
## 2026-02-11
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- Draw.io ([#11788](https://github.com/community-scripts/ProxmoxVE/pull/11788))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- dispatcharr: include port 9191 in success-message [@MickLesk](https://github.com/MickLesk) ([#11808](https://github.com/community-scripts/ProxmoxVE/pull/11808))
|
||||
- fix: make donetick 0.1.71 compatible [@tomfrenzel](https://github.com/tomfrenzel) ([#11804](https://github.com/community-scripts/ProxmoxVE/pull/11804))
|
||||
- Kasm: Support new version URL format without hash suffix [@MickLesk](https://github.com/MickLesk) ([#11787](https://github.com/community-scripts/ProxmoxVE/pull/11787))
|
||||
- LibreTranslate: Remove Torch [@tremor021](https://github.com/tremor021) ([#11783](https://github.com/community-scripts/ProxmoxVE/pull/11783))
|
||||
- Snowshare: fix update script [@TuroYT](https://github.com/TuroYT) ([#11726](https://github.com/community-scripts/ProxmoxVE/pull/11726))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- [Feature] OpenCloud: support PosixFS Collaborative Mode [@vhsdream](https://github.com/vhsdream) ([#11806](https://github.com/community-scripts/ProxmoxVE/pull/11806))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- core: respect EDITOR variable for config editing [@ls-root](https://github.com/ls-root) ([#11693](https://github.com/community-scripts/ProxmoxVE/pull/11693))
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Fix formatting in kutt.json notes section [@tiagodenoronha](https://github.com/tiagodenoronha) ([#11774](https://github.com/community-scripts/ProxmoxVE/pull/11774))
|
||||
|
||||
## 2026-02-10
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Immich: Pin version to 2.5.6 [@vhsdream](https://github.com/vhsdream) ([#11775](https://github.com/community-scripts/ProxmoxVE/pull/11775))
|
||||
- Libretranslate: Fix setuptools [@tremor021](https://github.com/tremor021) ([#11772](https://github.com/community-scripts/ProxmoxVE/pull/11772))
|
||||
- Element Synapse: prevent systemd invoke failure during apt install [@MickLesk](https://github.com/MickLesk) ([#11758](https://github.com/community-scripts/ProxmoxVE/pull/11758))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- Refactor: Slskd & Soularr [@vhsdream](https://github.com/vhsdream) ([#11674](https://github.com/community-scripts/ProxmoxVE/pull/11674))
|
||||
|
||||
### 🗑️ Deleted Scripts
|
||||
|
||||
- move paperless-exporter from LXC to addon ([#11737](https://github.com/community-scripts/ProxmoxVE/pull/11737))
|
||||
|
||||
### 🧰 Tools
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- feat: improve storage parsing & add guestname [@carlosmaroot](https://github.com/carlosmaroot) ([#11752](https://github.com/community-scripts/ProxmoxVE/pull/11752))
|
||||
|
||||
### 📂 Github
|
||||
|
||||
- Github-Version Workflow: include addon scripts in extraction [@MickLesk](https://github.com/MickLesk) ([#11757](https://github.com/community-scripts/ProxmoxVE/pull/11757))
|
||||
|
||||
### 🌐 Website
|
||||
|
||||
- #### 📝 Script Information
|
||||
|
||||
- Snowshare: fix typo in config file path on website [@BirdMakingStuff](https://github.com/BirdMakingStuff) ([#11754](https://github.com/community-scripts/ProxmoxVE/pull/11754))
|
||||
|
||||
## 2026-02-09
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- several scripts: add --clear to uv venv calls for uv 0.10 compatibility [@MickLesk](https://github.com/MickLesk) ([#11723](https://github.com/community-scripts/ProxmoxVE/pull/11723))
|
||||
- Koillection: ensure setup_composer is in update script [@MickLesk](https://github.com/MickLesk) ([#11734](https://github.com/community-scripts/ProxmoxVE/pull/11734))
|
||||
- PeaNUT: symlink server.js after update [@vhsdream](https://github.com/vhsdream) ([#11696](https://github.com/community-scripts/ProxmoxVE/pull/11696))
|
||||
- Umlautadaptarr: use release appsettings.json instead of hardcoded copy [@MickLesk](https://github.com/MickLesk) ([#11725](https://github.com/community-scripts/ProxmoxVE/pull/11725))
|
||||
- tracearr: prepare for next stable release [@durzo](https://github.com/durzo) ([#11673](https://github.com/community-scripts/ProxmoxVE/pull/11673))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- remove whiptail from update scripts for unattended update support [@MickLesk](https://github.com/MickLesk) ([#11712](https://github.com/community-scripts/ProxmoxVE/pull/11712))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Refactor: FileFlows [@tremor021](https://github.com/tremor021) ([#11108](https://github.com/community-scripts/ProxmoxVE/pull/11108))
|
||||
- Refactor: wger [@MickLesk](https://github.com/MickLesk) ([#11722](https://github.com/community-scripts/ProxmoxVE/pull/11722))
|
||||
- Nginx-UI: better User Handling | ACME [@MickLesk](https://github.com/MickLesk) ([#11715](https://github.com/community-scripts/ProxmoxVE/pull/11715))
|
||||
- NginxProxymanager: use better-sqlite3 [@MickLesk](https://github.com/MickLesk) ([#11708](https://github.com/community-scripts/ProxmoxVE/pull/11708))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- hwaccel: add libmfx-gen1.2 to Intel Arc setup for QSV support [@MickLesk](https://github.com/MickLesk) ([#11707](https://github.com/community-scripts/ProxmoxVE/pull/11707))
|
||||
|
||||
### 🧰 Tools
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- addons: ensure curl is installed before use [@MickLesk](https://github.com/MickLesk) ([#11718](https://github.com/community-scripts/ProxmoxVE/pull/11718))
|
||||
- Netbird (addon): add systemd ordering to start after Docker [@MickLesk](https://github.com/MickLesk) ([#11716](https://github.com/community-scripts/ProxmoxVE/pull/11716))
|
||||
|
||||
### ❔ Uncategorized
|
||||
|
||||
- Bichon: Update website [@tremor021](https://github.com/tremor021) ([#11711](https://github.com/community-scripts/ProxmoxVE/pull/11711))
|
||||
|
||||
## 2026-02-08
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- feat(healthchecks): add sendalerts service [@Mika56](https://github.com/Mika56) ([#11694](https://github.com/community-scripts/ProxmoxVE/pull/11694))
|
||||
- ComfyUI: Dynamic Fetch PyTorch Versions [@MickLesk](https://github.com/MickLesk) ([#11657](https://github.com/community-scripts/ProxmoxVE/pull/11657))
|
||||
|
||||
- #### 💥 Breaking Changes
|
||||
|
||||
- Semaphore: switch from Debian to Ubuntu 24.04 [@MickLesk](https://github.com/MickLesk) ([#11670](https://github.com/community-scripts/ProxmoxVE/pull/11670))
|
||||
|
||||
## 2026-02-07
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- Checkmate ([#11672](https://github.com/community-scripts/ProxmoxVE/pull/11672))
|
||||
- Bichon ([#11671](https://github.com/community-scripts/ProxmoxVE/pull/11671))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- NocoDB: pin to v0.301.1 [@MickLesk](https://github.com/MickLesk) ([#11655](https://github.com/community-scripts/ProxmoxVE/pull/11655))
|
||||
- Pin Memos to v0.25.3 - last version with release binaries [@MickLesk](https://github.com/MickLesk) ([#11658](https://github.com/community-scripts/ProxmoxVE/pull/11658))
|
||||
- Downgrade: OpenProject | NginxProxyManager | Semaphore to Debian 12 due to persistent SHA1 issues [@MickLesk](https://github.com/MickLesk) ([#11654](https://github.com/community-scripts/ProxmoxVE/pull/11654))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- tools: fallback to previous release when asset is missing [@MickLesk](https://github.com/MickLesk) ([#11660](https://github.com/community-scripts/ProxmoxVE/pull/11660))
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- fix(setup): correctly auto-detect username when using --full [@ls-root](https://github.com/ls-root) ([#11650](https://github.com/community-scripts/ProxmoxVE/pull/11650))
|
||||
|
||||
### 🌐 Website
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- feat(frontend): add JSON script import functionality [@ls-root](https://github.com/ls-root) ([#11563](https://github.com/community-scripts/ProxmoxVE/pull/11563))
|
||||
|
||||
## 2026-02-06
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- Nightscout ([#11621](https://github.com/community-scripts/ProxmoxVE/pull/11621))
|
||||
- PVE LXC Apps Updater [@MickLesk](https://github.com/MickLesk) ([#11533](https://github.com/community-scripts/ProxmoxVE/pull/11533))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Immich: supress startup messages for immich-admin [@vhsdream](https://github.com/vhsdream) ([#11635](https://github.com/community-scripts/ProxmoxVE/pull/11635))
|
||||
- Semaphore: Change Ubuntu release from 'jammy' to 'noble' [@MickLesk](https://github.com/MickLesk) ([#11625](https://github.com/community-scripts/ProxmoxVE/pull/11625))
|
||||
- Pangolin: replace build:sqlite with db:generate + build [@MickLesk](https://github.com/MickLesk) ([#11616](https://github.com/community-scripts/ProxmoxVE/pull/11616))
|
||||
- [FIX] OpenCloud: path issues [@vhsdream](https://github.com/vhsdream) ([#11593](https://github.com/community-scripts/ProxmoxVE/pull/11593))
|
||||
- [FIX] Homepage: preserve public/images & public/icons if they exist [@vhsdream](https://github.com/vhsdream) ([#11594](https://github.com/community-scripts/ProxmoxVE/pull/11594))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- Shelfmark: remove Chromedriver dep, add URL_BASE env [@vhsdream](https://github.com/vhsdream) ([#11619](https://github.com/community-scripts/ProxmoxVE/pull/11619))
|
||||
- Immich: pin to v2.5.5 [@vhsdream](https://github.com/vhsdream) ([#11598](https://github.com/community-scripts/ProxmoxVE/pull/11598))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- refactor: homepage [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11605](https://github.com/community-scripts/ProxmoxVE/pull/11605))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- fix(core): spinner misalignment [@ls-root](https://github.com/ls-root) ([#11627](https://github.com/community-scripts/ProxmoxVE/pull/11627))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- [Fix] build.func: QOL grammar adjustment for Creating LXC message [@vhsdream](https://github.com/vhsdream) ([#11633](https://github.com/community-scripts/ProxmoxVE/pull/11633))
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- [gh] Update to the New Script request template [@tremor021](https://github.com/tremor021) ([#11612](https://github.com/community-scripts/ProxmoxVE/pull/11612))
|
||||
|
||||
### 🌐 Website
|
||||
|
||||
- #### 📝 Script Information
|
||||
|
||||
- Update LXC App Updater JSON to reflect tag override option [@vhsdream](https://github.com/vhsdream) ([#11626](https://github.com/community-scripts/ProxmoxVE/pull/11626))
|
||||
|
||||
### ❔ Uncategorized
|
||||
|
||||
- Opencloud: fix JSON [@vhsdream](https://github.com/vhsdream) ([#11617](https://github.com/community-scripts/ProxmoxVE/pull/11617))
|
||||
@@ -1,50 +0,0 @@
|
||||
#!/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: cobalt (cobaltgit)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||
# Source: https://ntfy.sh/
|
||||
|
||||
APP="Alpine-ntfy"
|
||||
var_tags="${var_tags:-notification}"
|
||||
var_cpu="${var_cpu:-1}"
|
||||
var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-2}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
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 /etc/ntfy ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
msg_info "Updating ntfy LXC"
|
||||
$STD apk -U upgrade
|
||||
setcap 'cap_net_bind_service=+ep' /usr/bin/ntfy
|
||||
msg_ok "Updated ntfy LXC"
|
||||
|
||||
msg_info "Restarting ntfy"
|
||||
rc-service ntfy restart
|
||||
msg_ok "Restarted ntfy"
|
||||
msg_ok "Updated successfully!"
|
||||
exit
|
||||
}
|
||||
|
||||
start
|
||||
build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}"
|
||||
@@ -1,67 +0,0 @@
|
||||
#!/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: MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://anytype.io
|
||||
|
||||
APP="Anytype-Server"
|
||||
var_tags="${var_tags:-notes;productivity;sync}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-4096}"
|
||||
var_disk="${var_disk:-16}"
|
||||
var_os="${var_os:-ubuntu}"
|
||||
var_version="${var_version:-24.04}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
variables
|
||||
color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
|
||||
if [[ ! -f /opt/anytype/any-sync-bundle ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if check_for_gh_release "anytype" "grishy/any-sync-bundle"; then
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop anytype
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
msg_info "Backing up Data"
|
||||
cp -r /opt/anytype/data /opt/anytype_data_backup
|
||||
msg_ok "Backed up Data"
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "anytype" "grishy/any-sync-bundle" "prebuild" "latest" "/opt/anytype" "any-sync-bundle_*_linux_amd64.tar.gz"
|
||||
chmod +x /opt/anytype/any-sync-bundle
|
||||
|
||||
msg_info "Restoring Data"
|
||||
cp -r /opt/anytype_data_backup/. /opt/anytype/data
|
||||
rm -rf /opt/anytype_data_backup
|
||||
msg_ok "Restored Data"
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start anytype
|
||||
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}:33010${CL}"
|
||||
echo -e "${INFO}${YW} Client config file:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}/opt/anytype/data/client-config.yml${CL}"
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/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: DragoQC | Co-Author: nickheyer
|
||||
# Author: DragoQC
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://discopanel.app/ | Github: https://github.com/nickheyer/discopanel
|
||||
|
||||
@@ -38,15 +38,34 @@ function update_script() {
|
||||
|
||||
msg_info "Creating Backup"
|
||||
mkdir -p /opt/discopanel_backup_temp
|
||||
cp /opt/discopanel/data/discopanel.db /opt/discopanel_backup_temp/discopanel.db
|
||||
cp -r /opt/discopanel/data/discopanel.db \
|
||||
/opt/discopanel/data/.recovery_key \
|
||||
/opt/discopanel_backup_temp/
|
||||
if [[ -d /opt/discopanel/data/servers ]]; then
|
||||
cp -r /opt/discopanel/data/servers /opt/discopanel_backup_temp/
|
||||
fi
|
||||
msg_ok "Created Backup"
|
||||
|
||||
fetch_and_deploy_gh_release "discopanel" "nickheyer/discopanel" "prebuild" "latest" "/opt/discopanel" "discopanel-linux-amd64.tar.gz"
|
||||
ln -sf /opt/discopanel/discopanel-linux-amd64 /opt/discopanel/discopanel
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "discopanel" "nickheyer/discopanel" "tarball" "latest" "/opt/discopanel"
|
||||
|
||||
msg_info "Setting up DiscoPanel"
|
||||
cd /opt/discopanel
|
||||
$STD make gen
|
||||
cd /opt/discopanel/web/discopanel
|
||||
$STD npm install
|
||||
$STD npm run build
|
||||
msg_ok "Built Web Interface"
|
||||
|
||||
setup_go
|
||||
|
||||
msg_info "Building DiscoPanel"
|
||||
cd /opt/discopanel
|
||||
$STD go build -o discopanel cmd/discopanel/main.go
|
||||
msg_ok "Built DiscoPanel"
|
||||
|
||||
msg_info "Restoring Data"
|
||||
mkdir -p /opt/discopanel/data
|
||||
mv /opt/discopanel_backup_temp/discopanel.db /opt/discopanel/data/discopanel.db
|
||||
cp -a /opt/discopanel_backup_temp/. /opt/discopanel/data/
|
||||
rm -rf /opt/discopanel_backup_temp
|
||||
msg_ok "Restored Data"
|
||||
|
||||
|
||||
@@ -110,9 +110,7 @@ function update_script() {
|
||||
|
||||
msg_info "Building Frontend"
|
||||
cd /opt/dispatcharr/frontend
|
||||
node -e "const p=require('./package.json');p.overrides=p.overrides||{};p.overrides['webworkify-webpack']='2.1.3';require('fs').writeFileSync('package.json',JSON.stringify(p,null,2));"
|
||||
rm -f package-lock.json
|
||||
$STD npm install --no-audit --progress=false
|
||||
$STD npm install --legacy-peer-deps
|
||||
$STD npm run build
|
||||
msg_ok "Built Frontend"
|
||||
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
#!/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: MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/qdm12/gluetun
|
||||
|
||||
APP="Gluetun"
|
||||
var_tags="${var_tags:-vpn;wireguard;openvpn}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-8}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
var_tun="${var_tun:-yes}"
|
||||
|
||||
header_info "$APP"
|
||||
variables
|
||||
color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
|
||||
if [[ ! -f /usr/local/bin/gluetun ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if check_for_gh_release "gluetun" "qdm12/gluetun"; then
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop gluetun
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "gluetun" "qdm12/gluetun" "tarball"
|
||||
|
||||
msg_info "Building Gluetun"
|
||||
cd /opt/gluetun
|
||||
$STD go mod download
|
||||
CGO_ENABLED=0 $STD go build -trimpath -ldflags="-s -w" -o /usr/local/bin/gluetun ./cmd/gluetun/
|
||||
msg_ok "Built Gluetun"
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start gluetun
|
||||
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}:8000${CL}"
|
||||
@@ -1,6 +0,0 @@
|
||||
___ __ _ __ ____
|
||||
/ | / /___ (_)___ ___ ____ / /_/ __/_ __
|
||||
/ /| | / / __ \/ / __ \/ _ \______/ __ \/ __/ /_/ / / /
|
||||
/ ___ |/ / /_/ / / / / / __/_____/ / / / /_/ __/ /_/ /
|
||||
/_/ |_/_/ .___/_/_/ /_/\___/ /_/ /_/\__/_/ \__, /
|
||||
/_/ /____/
|
||||
@@ -1,6 +0,0 @@
|
||||
___ __ _____
|
||||
/ | ____ __ __/ /___ ______ ___ / ___/___ ______ _____ _____
|
||||
/ /| | / __ \/ / / / __/ / / / __ \/ _ \______\__ \/ _ \/ ___/ | / / _ \/ ___/
|
||||
/ ___ |/ / / / /_/ / /_/ /_/ / /_/ / __/_____/__/ / __/ / | |/ / __/ /
|
||||
/_/ |_/_/ /_/\__, /\__/\__, / .___/\___/ /____/\___/_/ |___/\___/_/
|
||||
/____/ /____/_/
|
||||
@@ -1,6 +0,0 @@
|
||||
________ __
|
||||
/ ____/ /_ _____ / /___ ______
|
||||
/ / __/ / / / / _ \/ __/ / / / __ \
|
||||
/ /_/ / / /_/ / __/ /_/ /_/ / / / /
|
||||
\____/_/\__,_/\___/\__/\__,_/_/ /_/
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
_____ ___ __ ____
|
||||
/ ___/____ / (_) /_ / __ \_________
|
||||
\__ \/ __ \/ / / __/_____/ /_/ / ___/ __ \
|
||||
___/ / /_/ / / / /_/_____/ ____/ / / /_/ /
|
||||
/____/ .___/_/_/\__/ /_/ /_/ \____/
|
||||
/_/
|
||||
@@ -1,6 +0,0 @@
|
||||
__ __ __ __
|
||||
\ \/ /___ _____ ___ / /__________ ______/ /__
|
||||
\ / __ `/ __ `__ \/ __/ ___/ __ `/ ___/ //_/
|
||||
/ / /_/ / / / / / / /_/ / / /_/ / /__/ ,<
|
||||
/_/\__,_/_/ /_/ /_/\__/_/ \__,_/\___/_/|_|
|
||||
|
||||
39
ct/immich.sh
39
ct/immich.sh
@@ -76,7 +76,7 @@ EOF
|
||||
SOURCE_DIR=${STAGING_DIR}/image-source
|
||||
cd /tmp
|
||||
if [[ -f ~/.intel_version ]]; then
|
||||
curl_with_retry "https://raw.githubusercontent.com/immich-app/immich/refs/heads/main/machine-learning/Dockerfile" "Dockerfile"
|
||||
curl -fsSLO https://raw.githubusercontent.com/immich-app/immich/refs/heads/main/machine-learning/Dockerfile
|
||||
readarray -t INTEL_URLS < <(
|
||||
sed -n "/intel-[igc|opencl]/p" ./Dockerfile | awk '{print $3}'
|
||||
sed -n "/libigdgmm12/p" ./Dockerfile | awk '{print $3}'
|
||||
@@ -85,7 +85,7 @@ EOF
|
||||
if [[ "$INTEL_RELEASE" != "$(cat ~/.intel_version)" ]]; then
|
||||
msg_info "Updating Intel iGPU dependencies"
|
||||
for url in "${INTEL_URLS[@]}"; do
|
||||
curl_with_retry "$url" "$(basename "$url")"
|
||||
curl -fsSLO "$url"
|
||||
done
|
||||
$STD apt-mark unhold libigdgmm12
|
||||
$STD apt install -y --allow-downgrades ./libigdgmm12*.deb
|
||||
@@ -109,7 +109,7 @@ EOF
|
||||
msg_ok "Image-processing libraries up to date"
|
||||
fi
|
||||
|
||||
RELEASE="v2.5.6"
|
||||
RELEASE="2.5.6"
|
||||
if check_for_gh_release "Immich" "immich-app/immich" "${RELEASE}"; then
|
||||
if [[ $(cat ~/.immich) > "2.5.1" ]]; then
|
||||
msg_info "Enabling Maintenance Mode"
|
||||
@@ -133,7 +133,7 @@ EOF
|
||||
$STD sudo -u postgres psql -d immich -c "REINDEX INDEX face_index;"
|
||||
$STD sudo -u postgres psql -d immich -c "REINDEX INDEX clip_index;"
|
||||
fi
|
||||
ensure_dependencies ccache gcc-13 g++-13
|
||||
ensure_dependencies ccache
|
||||
|
||||
INSTALL_DIR="/opt/${APP}"
|
||||
UPLOAD_DIR="$(sed -n '/^IMMICH_MEDIA_LOCATION/s/[^=]*=//p' /opt/immich/.env)"
|
||||
@@ -165,8 +165,8 @@ EOF
|
||||
)
|
||||
|
||||
setup_uv
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Immich" "immich-app/immich" "tarball" "${RELEASE}" "$SRC_DIR"
|
||||
PNPM_VERSION="$(jq -r '.packageManager | split("@")[1] | split("+")[0]' ${SRC_DIR}/package.json)"
|
||||
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"
|
||||
@@ -217,36 +217,15 @@ EOF
|
||||
chown -R immich:immich "$INSTALL_DIR"
|
||||
chown immich:immich ./uv.lock
|
||||
export VIRTUAL_ENV="${ML_DIR}"/ml-venv
|
||||
export UV_HTTP_TIMEOUT=300
|
||||
if [[ -f ~/.openvino ]]; then
|
||||
ML_PYTHON="python3.13"
|
||||
msg_info "Pre-installing Python ${ML_PYTHON} for machine-learning"
|
||||
for attempt in $(seq 1 3); do
|
||||
$STD sudo --preserve-env=VIRTUAL_ENV -nu immich uv python install "${ML_PYTHON}" && break
|
||||
[[ $attempt -lt 3 ]] && msg_warn "Python download attempt $attempt failed, retrying..." && sleep 5
|
||||
done
|
||||
msg_ok "Pre-installed Python ${ML_PYTHON}"
|
||||
msg_info "Updating HW-accelerated machine-learning"
|
||||
$STD uv add --no-sync --optional openvino onnxruntime-openvino==1.24.1 --active -n -p "${ML_PYTHON}" --managed-python
|
||||
for attempt in $(seq 1 3); do
|
||||
$STD sudo --preserve-env=VIRTUAL_ENV,UV_HTTP_TIMEOUT -nu immich uv sync --extra openvino --no-dev --active --link-mode copy -n -p "${ML_PYTHON}" --managed-python && break
|
||||
[[ $attempt -lt 3 ]] && msg_warn "uv sync attempt $attempt failed, retrying..." && sleep 10
|
||||
done
|
||||
$STD uv add --no-sync --optional openvino onnxruntime-openvino==1.24.1 --active -n -p python3.13 --managed-python
|
||||
$STD sudo --preserve-env=VIRTUAL_ENV -nu immich uv sync --extra openvino --no-dev --active --link-mode copy -n -p python3.13 --managed-python
|
||||
patchelf --clear-execstack "${VIRTUAL_ENV}/lib/python3.13/site-packages/onnxruntime/capi/onnxruntime_pybind11_state.cpython-313-x86_64-linux-gnu.so"
|
||||
msg_ok "Updated HW-accelerated machine-learning"
|
||||
else
|
||||
ML_PYTHON="python3.11"
|
||||
msg_info "Pre-installing Python ${ML_PYTHON} for machine-learning"
|
||||
for attempt in $(seq 1 3); do
|
||||
$STD sudo --preserve-env=VIRTUAL_ENV -nu immich uv python install "${ML_PYTHON}" && break
|
||||
[[ $attempt -lt 3 ]] && msg_warn "Python download attempt $attempt failed, retrying..." && sleep 5
|
||||
done
|
||||
msg_ok "Pre-installed Python ${ML_PYTHON}"
|
||||
msg_info "Updating machine-learning"
|
||||
for attempt in $(seq 1 3); do
|
||||
$STD sudo --preserve-env=VIRTUAL_ENV,UV_HTTP_TIMEOUT -nu immich uv sync --extra cpu --no-dev --active --link-mode copy -n -p "${ML_PYTHON}" --managed-python && break
|
||||
[[ $attempt -lt 3 ]] && msg_warn "uv sync attempt $attempt failed, retrying..." && sleep 10
|
||||
done
|
||||
$STD sudo --preserve-env=VIRTUAL_ENV -nu immich uv sync --extra cpu --no-dev --active --link-mode copy -n -p python3.11 --managed-python
|
||||
msg_ok "Updated machine-learning"
|
||||
fi
|
||||
cd "$SRC_DIR"
|
||||
|
||||
@@ -30,14 +30,9 @@ function update_script() {
|
||||
fi
|
||||
setup_mariadb
|
||||
|
||||
msg_info "Updating ITSM-NG"
|
||||
msg_info "Updating LXC"
|
||||
$STD apt update
|
||||
$STD apt -y upgrade
|
||||
chown -R www-data:www-data /var/lib/itsm-ng
|
||||
mkdir -p /usr/share/itsm-ng/css/palettes
|
||||
chown -R www-data:www-data /usr/share/itsm-ng/css
|
||||
chown -R www-data:www-data /usr/share/itsm-ng/css_compiled
|
||||
chown www-data:www-data /etc/itsm-ng/config_db.php
|
||||
msg_ok "Updated successfully!"
|
||||
exit
|
||||
}
|
||||
|
||||
@@ -39,23 +39,14 @@ function update_script() {
|
||||
msg_ok "Updated Intel Dependencies"
|
||||
fi
|
||||
|
||||
msg_info "Setting up Jellyfin Repository"
|
||||
setup_deb822_repo \
|
||||
"jellyfin" \
|
||||
"https://repo.jellyfin.org/jellyfin_team.gpg.key" \
|
||||
"https://repo.jellyfin.org/$(get_os_info id)" \
|
||||
"$(get_os_info codename)"
|
||||
msg_ok "Set up Jellyfin Repository"
|
||||
|
||||
msg_info "Updating Jellyfin"
|
||||
ensure_dependencies libjemalloc2
|
||||
if [[ ! -f /usr/lib/libjemalloc.so ]]; then
|
||||
ln -sf /usr/lib/x86_64-linux-gnu/libjemalloc.so.2 /usr/lib/libjemalloc.so
|
||||
fi
|
||||
$STD apt update
|
||||
$STD apt -y upgrade
|
||||
$STD apt -y --with-new-pkgs upgrade jellyfin jellyfin-server jellyfin-ffmpeg7
|
||||
ln -sf /usr/lib/jellyfin-ffmpeg/ffmpeg /usr/bin/ffmpeg
|
||||
ln -sf /usr/lib/jellyfin-ffmpeg/ffprobe /usr/bin/ffprobe
|
||||
$STD apt -y --with-new-pkgs upgrade jellyfin jellyfin-server
|
||||
msg_ok "Updated Jellyfin"
|
||||
msg_ok "Updated successfully!"
|
||||
exit
|
||||
|
||||
@@ -23,17 +23,16 @@ function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
RELEASE="0.301.1"
|
||||
if [[ ! -f /etc/systemd/system/nocodb.service ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
if check_for_gh_release "nocodb" "nocodb/nocodb" "${RELEASE}"; then
|
||||
if check_for_gh_release "nocodb" "nocodb/nocodb" "0.301.1"; then
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop nocodb
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
fetch_and_deploy_gh_release "nocodb" "nocodb/nocodb" "singlefile" "${RELEASE}" "/opt/nocodb/" "Noco-linux-x64"
|
||||
fetch_and_deploy_gh_release "nocodb" "nocodb/nocodb" "singlefile" "0.301.1" "/opt/nocodb/" "Noco-linux-x64"
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start nocodb
|
||||
|
||||
@@ -9,7 +9,7 @@ APP="Owncast"
|
||||
var_tags="${var_tags:-broadcasting}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-10}"
|
||||
var_disk="${var_disk:-2}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
@@ -8,7 +8,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
||||
APP="Paperless-ngx"
|
||||
var_tags="${var_tags:-document;management}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-3072}"
|
||||
var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-12}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
|
||||
@@ -36,9 +36,8 @@ function update_script() {
|
||||
read -r
|
||||
fi
|
||||
|
||||
RELEASE="v1.4.2"
|
||||
NODE_VERSION="24" setup_nodejs
|
||||
if check_for_gh_release "PatchMon" "PatchMon/PatchMon" "${RELEASE}"; then
|
||||
if check_for_gh_release "PatchMon" "PatchMon/PatchMon" "v1.4.2"; then
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop patchmon-server
|
||||
msg_ok "Stopped Service"
|
||||
@@ -48,7 +47,7 @@ function update_script() {
|
||||
cp /opt/patchmon/frontend/.env /opt/frontend.env
|
||||
msg_ok "Backup Created"
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "PatchMon" "PatchMon/PatchMon" "tarball" "${RELEASE}" "/opt/patchmon"
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "PatchMon" "PatchMon/PatchMon" "tarball" "v1.4.2" "/opt/patchmon"
|
||||
|
||||
msg_info "Updating PatchMon"
|
||||
VERSION=$(get_latest_github_release "PatchMon/PatchMon")
|
||||
|
||||
@@ -23,19 +23,18 @@ function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
RELEASE="0.10.0"
|
||||
if [[ ! -d /opt/plant-it ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
setup_mariadb
|
||||
if check_for_gh_release "plant-it" "MDeLuise/plant-it" "${RELEASE}"; then
|
||||
if check_for_gh_release "plant-it" "MDeLuise/plant-it"; then
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop plant-it
|
||||
msg_info "Stopped Service"
|
||||
|
||||
USE_ORIGINAL_FILENAME="true" fetch_and_deploy_gh_release "plant-it" "MDeLuise/plant-it" "singlefile" "${RELEASE}" "/opt/plant-it/backend" "server.jar"
|
||||
fetch_and_deploy_gh_release "plant-it-front" "MDeLuise/plant-it" "prebuild" "${RELEASE}" "/opt/plant-it/frontend" "client.tar.gz"
|
||||
USE_ORIGINAL_FILENAME="true" fetch_and_deploy_gh_release "plant-it" "MDeLuise/plant-it" "singlefile" "0.10.0" "/opt/plant-it/backend" "server.jar"
|
||||
fetch_and_deploy_gh_release "plant-it-front" "MDeLuise/plant-it" "prebuild" "0.10.0" "/opt/plant-it/frontend" "client.tar.gz"
|
||||
msg_warn "Application is updated to latest Web version (v0.10.0). There will be no more updates available."
|
||||
msg_warn "Please read: https://github.com/MDeLuise/plant-it/releases/tag/1.0.0"
|
||||
|
||||
|
||||
20
ct/plex.sh
20
ct/plex.sh
@@ -46,11 +46,11 @@ function update_script() {
|
||||
"main"
|
||||
msg_ok "Migrated to new Plex repository"
|
||||
fi
|
||||
elif compgen -G "/etc/apt/sources.list.d/plex*.list" >/dev/null; then
|
||||
elif [[ -f /etc/apt/sources.list.d/plexmediaserver.list ]]; then
|
||||
msg_info "Migrating to new Plex repository (deb822)"
|
||||
rm -f /etc/apt/sources.list.d/plex*.list
|
||||
rm -f /etc/apt/sources.list.d/plexmediaserver.list
|
||||
rm -f /etc/apt/sources.list.d/plex*
|
||||
rm -f /usr/share/keyrings/PlexSign.asc
|
||||
rm -f /usr/share/keyrings/plexmediaserver.v2.gpg
|
||||
setup_deb822_repo \
|
||||
"plexmediaserver" \
|
||||
"https://downloads.plex.tv/plex-keys/PlexSign.v2.key" \
|
||||
@@ -58,15 +58,6 @@ function update_script() {
|
||||
"public" \
|
||||
"main"
|
||||
msg_ok "Migrated to new Plex repository (deb822)"
|
||||
elif [[ ! -f /etc/apt/sources.list.d/plexmediaserver.sources ]]; then
|
||||
msg_info "Setting up Plex repository"
|
||||
setup_deb822_repo \
|
||||
"plexmediaserver" \
|
||||
"https://downloads.plex.tv/plex-keys/PlexSign.v2.key" \
|
||||
"https://repo.plex.tv/deb/" \
|
||||
"public" \
|
||||
"main"
|
||||
msg_ok "Set up Plex repository"
|
||||
fi
|
||||
if [[ -f /usr/local/bin/plexupdate ]] || [[ -d /opt/plexupdate ]]; then
|
||||
msg_info "Removing legacy plexupdate"
|
||||
@@ -79,11 +70,6 @@ function update_script() {
|
||||
$STD apt update
|
||||
$STD apt install -y plexmediaserver
|
||||
msg_ok "Updated Plex Media Server"
|
||||
|
||||
msg_info "Restarting Plex Media Server"
|
||||
systemctl restart plexmediaserver
|
||||
msg_ok "Restarted Plex Media Server"
|
||||
|
||||
msg_ok "Updated successfully!"
|
||||
exit
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
if [[ ! -f /etc/containers/systemd/homeassistant.container ]]; then
|
||||
if [[ ! -f /etc/systemd/system/homeassistant.service ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
@@ -60,4 +60,4 @@ description
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}/install for the initial setup${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}"
|
||||
|
||||
@@ -9,7 +9,7 @@ APP="PVE-Scripts-Local"
|
||||
var_tags="${var_tags:-pve-scripts-local}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-4096}"
|
||||
var_disk="${var_disk:-10}"
|
||||
var_disk="${var_disk:-4}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
34
ct/reitti.sh
34
ct/reitti.sh
@@ -89,49 +89,17 @@ EOF
|
||||
msg_ok "Started Service"
|
||||
msg_ok "Updated successfully!"
|
||||
fi
|
||||
|
||||
if check_for_gh_release "photon" "komoot/photon"; then
|
||||
if [[ -f "$HOME/.photon" ]] && [[ "$(cat "$HOME/.photon")" == 0.7 ]]; then
|
||||
CURRENT_VERSION="$(<"$HOME/.photon")"
|
||||
echo
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "Photon v1 upgrade detected (breaking change)"
|
||||
echo
|
||||
echo "Your current version: $CURRENT_VERSION"
|
||||
echo
|
||||
echo "Photon v1 requires a manual migration before updating."
|
||||
echo
|
||||
echo "You need to:"
|
||||
echo " 1. Remove existing geocoding data (not actual reitti data):"
|
||||
echo " rm -rf /opt/photon_data"
|
||||
echo
|
||||
echo " 2. Follow the inial setup guide again:"
|
||||
echo " https://github.com/community-scripts/ProxmoxVE/discussions/8737"
|
||||
echo
|
||||
echo " 3. Re-download and import Photon data for v1"
|
||||
echo
|
||||
read -rp "Do you want to continue anyway? (y/N): " CONTINUE
|
||||
echo
|
||||
|
||||
if [[ ! "$CONTINUE" =~ ^[Yy]$ ]]; then
|
||||
msg_info "Migration required. Update cancelled."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
msg_warn "Continuing without migration may break Photon in the future!"
|
||||
fi
|
||||
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop photon
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
rm -f /opt/photon/photon.jar
|
||||
USE_ORIGINAL_FILENAME="true" fetch_and_deploy_gh_release "photon" "komoot/photon" "singlefile" "latest" "/opt/photon" "photon-*.jar"
|
||||
USE_ORIGINAL_FILENAME="true" fetch_and_deploy_gh_release "photon" "komoot/photon" "singlefile" "latest" "/opt/photon" "photon-0*.jar"
|
||||
mv /opt/photon/photon-*.jar /opt/photon/photon.jar
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start photon
|
||||
systemctl restart nginx
|
||||
msg_ok "Started Service"
|
||||
msg_ok "Updated successfully!"
|
||||
fi
|
||||
|
||||
@@ -128,8 +128,6 @@ EOF
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "seerr" "seerr-team/seerr" "tarball"
|
||||
|
||||
ensure_dependencies build-essential python3-setuptools
|
||||
|
||||
msg_info "Updating PNPM Version"
|
||||
pnpm_desired=$(grep -Po '"pnpm":\s*"\K[^"]+' /opt/seerr/package.json)
|
||||
NODE_VERSION="22" NODE_MODULE="pnpm@$pnpm_desired" setup_nodejs
|
||||
|
||||
@@ -51,7 +51,7 @@ function update_script() {
|
||||
|
||||
msg_info "Updating Sparky Fitness Backend"
|
||||
cd /opt/sparkyfitness/SparkyFitnessServer
|
||||
$STD pnpm install
|
||||
$STD npm install
|
||||
msg_ok "Updated Sparky Fitness Backend"
|
||||
|
||||
msg_info "Updating Sparky Fitness Frontend (Patience)"
|
||||
@@ -62,27 +62,6 @@ function update_script() {
|
||||
cp -a /opt/sparkyfitness/SparkyFitnessFrontend/dist/. /var/www/sparkyfitness/
|
||||
msg_ok "Updated Sparky Fitness Frontend"
|
||||
|
||||
msg_info "Refreshing SparkyFitness Service"
|
||||
cat <<EOF >/etc/systemd/system/sparkyfitness-server.service
|
||||
[Unit]
|
||||
Description=SparkyFitness Backend Service
|
||||
After=network.target postgresql.service
|
||||
Requires=postgresql.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/opt/sparkyfitness/SparkyFitnessServer
|
||||
EnvironmentFile=/etc/sparkyfitness/.env
|
||||
ExecStart=/opt/sparkyfitness/SparkyFitnessServer/node_modules/.bin/tsx SparkyFitnessServer.js
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
msg_ok "Refreshed SparkyFitness Service"
|
||||
|
||||
msg_info "Restoring data"
|
||||
cp -r /opt/sparkyfitness_backup/. /opt/sparkyfitness/SparkyFitnessServer/
|
||||
rm -rf /opt/sparkyfitness_backup
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
#!/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: johanngrobe
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/oss-apps/split-pro
|
||||
|
||||
APP="Split-Pro"
|
||||
var_tags="${var_tags:-finance;expense-sharing}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-4096}"
|
||||
var_disk="${var_disk:-6}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
variables
|
||||
color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
|
||||
if [[ ! -d /opt/split-pro ]]; then
|
||||
msg_error "No Split Pro Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if check_for_gh_release "split-pro" "oss-apps/split-pro"; then
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop split-pro
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
msg_info "Backing up Data"
|
||||
cp /opt/split-pro/.env /opt/split-pro.env
|
||||
msg_ok "Backed up Data"
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "split-pro" "oss-apps/split-pro" "tarball"
|
||||
|
||||
msg_info "Building Application"
|
||||
cd /opt/split-pro
|
||||
$STD pnpm install --frozen-lockfile
|
||||
$STD pnpm build
|
||||
cp /opt/split-pro.env /opt/split-pro/.env
|
||||
rm -f /opt/split-pro.env
|
||||
ln -sf /opt/split-pro_data/uploads /opt/split-pro/uploads
|
||||
$STD pnpm exec prisma migrate deploy
|
||||
msg_ok "Built Application"
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start split-pro
|
||||
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}:3000${CL}"
|
||||
@@ -51,7 +51,6 @@ function update_script() {
|
||||
$STD source /opt/Tautulli/.venv/bin/activate
|
||||
$STD uv pip install -r requirements.txt
|
||||
$STD uv pip install pyopenssl
|
||||
$STD uv pip install "setuptools<81"
|
||||
msg_ok "Updated Tautulli"
|
||||
|
||||
msg_info "Restoring config and database"
|
||||
|
||||
@@ -33,16 +33,12 @@ function update_script() {
|
||||
$STD apt upgrade -y
|
||||
rm -rf /opt/tdarr/Tdarr_Updater
|
||||
cd /opt/tdarr
|
||||
RELEASE=$(curl_with_retry "https://f000.backblazeb2.com/file/tdarrs/versions.json" "-" | grep -oP '(?<="Tdarr_Updater": ")[^"]+' | grep linux_x64 | head -n 1)
|
||||
curl_with_retry "$RELEASE" "Tdarr_Updater.zip"
|
||||
RELEASE=$(curl -fsSL https://f000.backblazeb2.com/file/tdarrs/versions.json | grep -oP '(?<="Tdarr_Updater": ")[^"]+' | grep linux_x64 | head -n 1)
|
||||
curl -fsSL "$RELEASE" -o Tdarr_Updater.zip
|
||||
$STD unzip Tdarr_Updater.zip
|
||||
chmod +x Tdarr_Updater
|
||||
$STD ./Tdarr_Updater
|
||||
rm -rf /opt/tdarr/Tdarr_Updater.zip
|
||||
[[ -f /opt/tdarr/Tdarr_Server/Tdarr_Server ]] || {
|
||||
msg_error "Tdarr_Updater failed — tdarr.io may be blocked by local DNS"
|
||||
exit 250
|
||||
}
|
||||
msg_ok "Updated Tdarr"
|
||||
msg_ok "Updated successfully!"
|
||||
exit
|
||||
|
||||
116
ct/termix.sh
116
ct/termix.sh
@@ -29,116 +29,10 @@ function update_script() {
|
||||
exit
|
||||
fi
|
||||
|
||||
if check_for_gh_tag "guacd" "apache/guacamole-server"; then
|
||||
msg_info "Stopping guacd"
|
||||
systemctl stop guacd 2>/dev/null || true
|
||||
msg_ok "Stopped guacd"
|
||||
|
||||
ensure_dependencies \
|
||||
libcairo2-dev \
|
||||
libjpeg62-turbo-dev \
|
||||
libpng-dev \
|
||||
libtool-bin \
|
||||
uuid-dev \
|
||||
libvncserver-dev \
|
||||
freerdp3-dev \
|
||||
libssh2-1-dev \
|
||||
libtelnet-dev \
|
||||
libwebsockets-dev \
|
||||
libpulse-dev \
|
||||
libvorbis-dev \
|
||||
libwebp-dev \
|
||||
libssl-dev \
|
||||
libpango1.0-dev \
|
||||
libswscale-dev \
|
||||
libavcodec-dev \
|
||||
libavutil-dev \
|
||||
libavformat-dev
|
||||
|
||||
msg_info "Updating Guacamole Server (guacd)"
|
||||
fetch_and_deploy_gh_tag "guacd" "apache/guacamole-server" "${CHECK_UPDATE_RELEASE}" "/opt/guacamole-server"
|
||||
cd /opt/guacamole-server
|
||||
export CPPFLAGS="-Wno-error=deprecated-declarations"
|
||||
$STD autoreconf -fi
|
||||
$STD ./configure --with-init-dir=/etc/init.d --enable-allow-freerdp-snapshots
|
||||
$STD make
|
||||
$STD make install
|
||||
$STD ldconfig
|
||||
cd /opt
|
||||
rm -rf /opt/guacamole-server
|
||||
msg_ok "Updated Guacamole Server (guacd) to ${CHECK_UPDATE_RELEASE}"
|
||||
|
||||
if [[ ! -f /etc/guacamole/guacd.conf ]]; then
|
||||
mkdir -p /etc/guacamole
|
||||
cat <<EOF >/etc/guacamole/guacd.conf
|
||||
[server]
|
||||
bind_host = 127.0.0.1
|
||||
bind_port = 4822
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [[ ! -f /etc/systemd/system/guacd.service ]] || grep -q "Type=forking" /etc/systemd/system/guacd.service 2>/dev/null; then
|
||||
cat <<EOF >/etc/systemd/system/guacd.service
|
||||
[Unit]
|
||||
Description=Guacamole Proxy Daemon (guacd)
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/local/sbin/guacd -f -b 127.0.0.1 -l 4822
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
fi
|
||||
|
||||
if ! grep -q "guacd.service" /etc/systemd/system/termix.service 2>/dev/null; then
|
||||
sed -i '/^After=network.target/s/$/ guacd.service/' /etc/systemd/system/termix.service
|
||||
sed -i '/^\[Unit\]/a Wants=guacd.service' /etc/systemd/system/termix.service
|
||||
fi
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable -q --now guacd
|
||||
fi
|
||||
|
||||
if check_for_gh_release "termix" "Termix-SSH/Termix"; then
|
||||
msg_info "Stopping Termix"
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop termix
|
||||
msg_ok "Stopped Termix"
|
||||
|
||||
msg_info "Migrating Configuration"
|
||||
if [[ ! -f /opt/termix/.env ]]; then
|
||||
cat <<EOF >/opt/termix/.env
|
||||
NODE_ENV=production
|
||||
DATA_DIR=/opt/termix/data
|
||||
GUACD_HOST=127.0.0.1
|
||||
GUACD_PORT=4822
|
||||
EOF
|
||||
fi
|
||||
if ! grep -q "EnvironmentFile" /etc/systemd/system/termix.service 2>/dev/null; then
|
||||
cat <<EOF >/etc/systemd/system/termix.service
|
||||
[Unit]
|
||||
Description=Termix Backend
|
||||
After=network.target guacd.service
|
||||
Wants=guacd.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
WorkingDirectory=/opt/termix
|
||||
EnvironmentFile=/opt/termix/.env
|
||||
ExecStart=/usr/bin/node /opt/termix/dist/backend/backend/starter.js
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
msg_ok "Migrated Configuration"
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
msg_info "Backing up Data"
|
||||
cp -r /opt/termix/data /opt/termix_data_backup
|
||||
@@ -201,16 +95,16 @@ EOF
|
||||
sed -i 's|/app/html|/opt/termix/html|g' /etc/nginx/nginx.conf
|
||||
sed -i 's|/app/nginx|/opt/termix/nginx|g' /etc/nginx/nginx.conf
|
||||
sed -i 's|listen ${PORT};|listen 80;|g' /etc/nginx/nginx.conf
|
||||
|
||||
|
||||
nginx -t && systemctl reload nginx
|
||||
msg_ok "Updated Nginx Configuration"
|
||||
else
|
||||
msg_warn "Nginx configuration not updated. If Termix doesn't work, restore from backup or update manually."
|
||||
fi
|
||||
|
||||
msg_info "Starting Termix"
|
||||
msg_info "Starting Service"
|
||||
systemctl start termix
|
||||
msg_ok "Started Termix"
|
||||
msg_ok "Started Service"
|
||||
msg_ok "Updated successfully!"
|
||||
fi
|
||||
exit
|
||||
|
||||
@@ -8,7 +8,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
||||
APP="Tracearr"
|
||||
var_tags="${var_tags:-media}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-4096}"
|
||||
var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-10}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
@@ -140,7 +140,7 @@ EOF
|
||||
msg_ok "Built Tracearr"
|
||||
|
||||
msg_info "Configuring Tracearr"
|
||||
sed -i "s|^APP_VERSION=.*|APP_VERSION=${CHECK_UPDATE_RELEASE#v}|" /data/tracearr/.env
|
||||
sed -i "s/^APP_VERSION=.*/APP_VERSION=$(cat /root/.tracearr)/" /data/tracearr/.env
|
||||
chmod 600 /data/tracearr/.env
|
||||
chown -R tracearr:tracearr /data/tracearr
|
||||
mkdir -p /data/backup
|
||||
|
||||
@@ -46,7 +46,7 @@ function update_script() {
|
||||
|
||||
msg_info "Updating Wishlist"
|
||||
cd /opt/wishlist
|
||||
$STD pnpm install --frozen-lockfile
|
||||
$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)
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
#!/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: MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/FuzzyGrim/Yamtrack
|
||||
|
||||
APP="Yamtrack"
|
||||
var_tags="${var_tags:-media;tracker;movies;anime}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-8}"
|
||||
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/yamtrack ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if check_for_gh_release "yamtrack" "FuzzyGrim/Yamtrack"; then
|
||||
msg_info "Stopping Services"
|
||||
systemctl stop yamtrack yamtrack-celery
|
||||
msg_ok "Stopped Services"
|
||||
|
||||
msg_info "Backing up Data"
|
||||
cp /opt/yamtrack/src/.env /opt/yamtrack_env.bak
|
||||
msg_ok "Backed up Data"
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "yamtrack" "FuzzyGrim/Yamtrack" "tarball"
|
||||
|
||||
msg_info "Installing Python Dependencies"
|
||||
cd /opt/yamtrack
|
||||
$STD uv venv .venv
|
||||
$STD uv pip install --no-cache-dir -r requirements.txt
|
||||
msg_ok "Installed Python Dependencies"
|
||||
|
||||
msg_info "Restoring Data"
|
||||
cp /opt/yamtrack_env.bak /opt/yamtrack/src/.env
|
||||
rm -f /opt/yamtrack_env.bak
|
||||
msg_ok "Restored Data"
|
||||
|
||||
msg_info "Updating Yamtrack"
|
||||
cd /opt/yamtrack/src
|
||||
$STD /opt/yamtrack/.venv/bin/python manage.py migrate
|
||||
$STD /opt/yamtrack/.venv/bin/python manage.py collectstatic --noinput
|
||||
msg_ok "Updated Yamtrack"
|
||||
|
||||
msg_info "Updating Nginx Configuration"
|
||||
cp /opt/yamtrack/nginx.conf /etc/nginx/nginx.conf
|
||||
sed -i 's|user abc;|user www-data;|' /etc/nginx/nginx.conf
|
||||
sed -i 's|/yamtrack/staticfiles/|/opt/yamtrack/src/staticfiles/|' /etc/nginx/nginx.conf
|
||||
$STD systemctl reload nginx
|
||||
msg_ok "Updated Nginx Configuration"
|
||||
|
||||
msg_info "Starting Services"
|
||||
systemctl start yamtrack yamtrack-celery
|
||||
msg_ok "Started Services"
|
||||
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}:8000${CL}"
|
||||
@@ -47,7 +47,7 @@ function update_script() {
|
||||
|
||||
msg_info "Installing Python Dependencies"
|
||||
cd /opt/yubal
|
||||
$STD uv sync --package yubal-api --no-dev --frozen
|
||||
$STD uv sync --no-dev --frozen
|
||||
msg_ok "Installed Python Dependencies"
|
||||
|
||||
msg_info "Starting Services"
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: cobalt (cobaltgit)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||
# Source: https://ntfy.sh/
|
||||
|
||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||
color
|
||||
verb_ip6
|
||||
catch_errors
|
||||
setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
|
||||
msg_info "Installing ntfy"
|
||||
$STD apk add --no-cache ntfy ntfy-openrc libcap
|
||||
sed -i '/^listen-http/s/^\(.*\)$/#\1\n/' /etc/ntfy/server.yml
|
||||
setcap 'cap_net_bind_service=+ep' /usr/bin/ntfy
|
||||
$STD rc-update add ntfy default
|
||||
$STD service ntfy start
|
||||
msg_ok "Installed ntfy"
|
||||
|
||||
motd_ssh
|
||||
customize
|
||||
@@ -1,81 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://anytype.io
|
||||
|
||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||
color
|
||||
verb_ip6
|
||||
catch_errors
|
||||
setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
|
||||
setup_mongodb
|
||||
|
||||
msg_info "Configuring MongoDB Replica Set"
|
||||
cat <<EOF >>/etc/mongod.conf
|
||||
|
||||
replication:
|
||||
replSetName: "rs0"
|
||||
EOF
|
||||
systemctl restart mongod
|
||||
sleep 3
|
||||
$STD mongosh --eval 'rs.initiate({_id: "rs0", members: [{_id: 0, host: "127.0.0.1:27017"}]})'
|
||||
msg_ok "Configured MongoDB Replica Set"
|
||||
|
||||
msg_info "Installing Redis Stack"
|
||||
setup_deb822_repo \
|
||||
"redis-stack" \
|
||||
"https://packages.redis.io/gpg" \
|
||||
"https://packages.redis.io/deb" \
|
||||
"jammy" \
|
||||
"main"
|
||||
$STD apt install -y redis-stack-server
|
||||
systemctl enable -q --now redis-stack-server
|
||||
msg_ok "Installed Redis Stack"
|
||||
|
||||
fetch_and_deploy_gh_release "anytype" "grishy/any-sync-bundle" "prebuild" "latest" "/opt/anytype" "any-sync-bundle_*_linux_amd64.tar.gz"
|
||||
chmod +x /opt/anytype/any-sync-bundle
|
||||
|
||||
msg_info "Configuring Anytype"
|
||||
mkdir -p /opt/anytype/data/storage
|
||||
cat <<EOF >/opt/anytype/.env
|
||||
ANY_SYNC_BUNDLE_CONFIG=/opt/anytype/data/bundle-config.yml
|
||||
ANY_SYNC_BUNDLE_CLIENT_CONFIG=/opt/anytype/data/client-config.yml
|
||||
ANY_SYNC_BUNDLE_INIT_STORAGE=/opt/anytype/data/storage/
|
||||
ANY_SYNC_BUNDLE_INIT_EXTERNAL_ADDRS=${LOCAL_IP}
|
||||
ANY_SYNC_BUNDLE_INIT_MONGO_URI=mongodb://127.0.0.1:27017/
|
||||
ANY_SYNC_BUNDLE_INIT_REDIS_URI=redis://127.0.0.1:6379/
|
||||
ANY_SYNC_BUNDLE_LOG_LEVEL=info
|
||||
EOF
|
||||
msg_ok "Configured Anytype"
|
||||
|
||||
msg_info "Creating Service"
|
||||
cat <<EOF >/etc/systemd/system/anytype.service
|
||||
[Unit]
|
||||
Description=Anytype Sync Server (any-sync-bundle)
|
||||
After=network-online.target mongod.service redis-stack-server.service
|
||||
Wants=network-online.target
|
||||
Requires=mongod.service redis-stack-server.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
WorkingDirectory=/opt/anytype
|
||||
EnvironmentFile=/opt/anytype/.env
|
||||
ExecStart=/opt/anytype/any-sync-bundle start-bundle
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl enable -q --now anytype
|
||||
msg_ok "Created Service"
|
||||
|
||||
motd_ssh
|
||||
customize
|
||||
cleanup_lxc
|
||||
@@ -35,6 +35,7 @@ setup_hwaccel
|
||||
msg_info "Installing Channels DVR Server (Patience)"
|
||||
cd /opt
|
||||
$STD bash <(curl -fsSL https://getchannels.com/dvr/setup.sh)
|
||||
sed -i -e 's/^sgx:x:104:$/render:x:104:root/' -e 's/^render:x:106:root$/sgx:x:106:/' /etc/group
|
||||
msg_ok "Installed Channels DVR Server"
|
||||
|
||||
motd_ssh
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: DragoQC | Co-Author: nickheyer
|
||||
# Author: DragoQC
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://discopanel.app/ | Github: https://github.com/nickheyer/discopanel
|
||||
|
||||
@@ -12,9 +12,25 @@ setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
|
||||
fetch_and_deploy_gh_release "discopanel" "nickheyer/discopanel" "prebuild" "latest" "/opt/discopanel" "discopanel-linux-amd64.tar.gz"
|
||||
msg_info "Installing Dependencies"
|
||||
$STD apt install -y build-essential
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
NODE_VERSION="22" setup_nodejs
|
||||
setup_go
|
||||
fetch_and_deploy_gh_release "discopanel" "nickheyer/discopanel" "tarball" "latest" "/opt/discopanel"
|
||||
setup_docker
|
||||
|
||||
msg_info "Setting up DiscoPanel"
|
||||
cd /opt/discopanel
|
||||
$STD make gen
|
||||
cd /opt/discopanel/web/discopanel
|
||||
$STD npm install
|
||||
$STD npm run build
|
||||
cd /opt/discopanel
|
||||
$STD go build -o discopanel cmd/discopanel/main.go
|
||||
msg_ok "Setup DiscoPanel"
|
||||
|
||||
msg_info "Creating Service"
|
||||
cat <<EOF >/etc/systemd/system/discopanel.service
|
||||
[Unit]
|
||||
@@ -23,7 +39,7 @@ After=network.target
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/opt/discopanel
|
||||
ExecStart=/opt/discopanel/discopanel-linux-amd64
|
||||
ExecStart=/opt/discopanel/discopanel
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
|
||||
@@ -66,9 +66,7 @@ CELERY_BROKER_URL=redis://localhost:6379/0
|
||||
DJANGO_SECRET_KEY=$DJANGO_SECRET
|
||||
EOF
|
||||
cd /opt/dispatcharr/frontend
|
||||
node -e "const p=require('./package.json');p.overrides=p.overrides||{};p.overrides['webworkify-webpack']='2.1.3';require('fs').writeFileSync('package.json',JSON.stringify(p,null,2));"
|
||||
rm -f package-lock.json
|
||||
$STD npm install --no-audit --progress=false
|
||||
$STD npm install --legacy-peer-deps
|
||||
$STD npm run build
|
||||
msg_ok "Configured Dispatcharr"
|
||||
|
||||
|
||||
@@ -13,9 +13,17 @@ setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
|
||||
setup_hwaccel
|
||||
|
||||
fetch_and_deploy_gh_release "emby" "MediaBrowser/Emby.Releases" "binary"
|
||||
|
||||
setup_hwaccel "emby"
|
||||
msg_info "Configuring Emby"
|
||||
if [[ "$CTTYPE" == "0" ]]; then
|
||||
sed -i -e 's/^ssl-cert:x:104:$/render:x:104:root,emby/' -e 's/^render:x:108:root,emby$/ssl-cert:x:108:/' /etc/group
|
||||
else
|
||||
sed -i -e 's/^ssl-cert:x:104:$/render:x:104:emby/' -e 's/^render:x:108:emby$/ssl-cert:x:108:/' /etc/group
|
||||
fi
|
||||
msg_ok "Configured Emby"
|
||||
|
||||
motd_ssh
|
||||
customize
|
||||
|
||||
@@ -146,7 +146,7 @@ ldconfig
|
||||
msg_ok "Built libUSB"
|
||||
|
||||
msg_info "Bootstrapping pip"
|
||||
curl_with_retry "https://bootstrap.pypa.io/get-pip.py" "/tmp/get-pip.py"
|
||||
wget -q https://bootstrap.pypa.io/get-pip.py -O /tmp/get-pip.py
|
||||
sed -i 's/args.append("setuptools")/args.append("setuptools==77.0.3")/' /tmp/get-pip.py
|
||||
$STD python3 /tmp/get-pip.py "pip"
|
||||
rm -f /tmp/get-pip.py
|
||||
@@ -169,13 +169,13 @@ NODE_VERSION="20" setup_nodejs
|
||||
|
||||
msg_info "Downloading Inference Models"
|
||||
mkdir -p /models /openvino-model
|
||||
curl_with_retry "https://github.com/google-coral/test_data/raw/release-frogfish/ssdlite_mobiledet_coco_qat_postprocess_edgetpu.tflite" "/edgetpu_model.tflite"
|
||||
curl_with_retry "https://github.com/google-coral/test_data/raw/release-frogfish/ssdlite_mobiledet_coco_qat_postprocess.tflite" "/models/cpu_model.tflite"
|
||||
wget -q -O /edgetpu_model.tflite https://github.com/google-coral/test_data/raw/release-frogfish/ssdlite_mobiledet_coco_qat_postprocess_edgetpu.tflite
|
||||
wget -q -O /models/cpu_model.tflite https://github.com/google-coral/test_data/raw/release-frogfish/ssdlite_mobiledet_coco_qat_postprocess.tflite
|
||||
cp /opt/frigate/labelmap.txt /labelmap.txt
|
||||
msg_ok "Downloaded Inference Models"
|
||||
|
||||
msg_info "Downloading Audio Model"
|
||||
curl_with_retry "https://www.kaggle.com/api/v1/models/google/yamnet/tfLite/classification-tflite/1/download" "/tmp/yamnet.tar.gz"
|
||||
wget -q -O /tmp/yamnet.tar.gz https://www.kaggle.com/api/v1/models/google/yamnet/tfLite/classification-tflite/1/download
|
||||
$STD tar xzf /tmp/yamnet.tar.gz -C /
|
||||
mv /1.tflite /cpu_audio_model.tflite
|
||||
cp /opt/frigate/audio-labelmap.txt /audio-labelmap.txt
|
||||
@@ -205,23 +205,13 @@ msg_ok "Installed OpenVino"
|
||||
|
||||
msg_info "Building OpenVino Model"
|
||||
cd /models
|
||||
curl_with_retry "http://download.tensorflow.org/models/object_detection/ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz" "ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz"
|
||||
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 python3 /opt/frigate/docker/main/build_ov_model.py &>/dev/null; then
|
||||
mkdir -p /openvino-model
|
||||
cp /models/ssdlite_mobilenet_v2.xml /openvino-model/
|
||||
cp /models/ssdlite_mobilenet_v2.bin /openvino-model/
|
||||
OV_LABELS=$(python3 -c "import omz_tools; import os; print(os.path.join(omz_tools.__path__[0], 'data/dataset_classes/coco_91cl_bkgr.txt'))" 2>/dev/null)
|
||||
if [[ -n "$OV_LABELS" && -f "$OV_LABELS" ]]; then
|
||||
ln -sf "$OV_LABELS" /openvino-model/coco_91cl_bkgr.txt
|
||||
else
|
||||
OV_LABELS=$(find /usr/local/lib -name "coco_91cl_bkgr.txt" 2>/dev/null | head -1)
|
||||
if [[ -n "$OV_LABELS" ]]; then
|
||||
ln -sf "$OV_LABELS" /openvino-model/coco_91cl_bkgr.txt
|
||||
else
|
||||
curl_with_retry "https://raw.githubusercontent.com/openvinotoolkit/open_model_zoo/master/data/dataset_classes/coco_91cl_bkgr.txt" "/openvino-model/coco_91cl_bkgr.txt"
|
||||
fi
|
||||
fi
|
||||
$STD ln -sf $(python3 -c "import omz_tools; import os; print(os.path.join(omz_tools.__path__[0], 'data/dataset_classes/coco_91cl_bkgr.txt'))") /openvino-model/coco_91cl_bkgr.txt
|
||||
sed -i 's/truck/car/g' /openvino-model/coco_91cl_bkgr.txt
|
||||
msg_ok "Built OpenVino Model"
|
||||
else
|
||||
@@ -246,7 +236,7 @@ msg_info "Configuring Frigate"
|
||||
mkdir -p /config /media/frigate
|
||||
cp -r /opt/frigate/config/. /config
|
||||
|
||||
curl_with_retry "https://github.com/intel-iot-devkit/sample-videos/raw/master/person-bicycle-car-detection.mp4" "/media/frigate/person-bicycle-car-detection.mp4"
|
||||
curl -fsSL "https://github.com/intel-iot-devkit/sample-videos/raw/master/person-bicycle-car-detection.mp4" -o "/media/frigate/person-bicycle-car-detection.mp4"
|
||||
|
||||
echo "tmpfs /tmp/cache tmpfs defaults 0 0" >>/etc/fstab
|
||||
|
||||
@@ -289,7 +279,7 @@ detect:
|
||||
enabled: false
|
||||
EOF
|
||||
|
||||
if grep -q -o -m1 -E 'avx[^ ]*|sse4_2' /proc/cpuinfo && [[ -f /openvino-model/ssdlite_mobilenet_v2.xml ]] && [[ -f /openvino-model/coco_91cl_bkgr.txt ]]; then
|
||||
if grep -q -o -m1 -E 'avx[^ ]*|sse4_2' /proc/cpuinfo; then
|
||||
cat <<EOF >>/config/config.yml
|
||||
ffmpeg:
|
||||
hwaccel_args: auto
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/qdm12/gluetun
|
||||
|
||||
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 \
|
||||
openvpn \
|
||||
wireguard-tools \
|
||||
iptables
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
msg_info "Configuring iptables"
|
||||
$STD update-alternatives --set iptables /usr/sbin/iptables-legacy
|
||||
$STD update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
|
||||
ln -sf /usr/sbin/openvpn /usr/sbin/openvpn2.6
|
||||
msg_ok "Configured iptables"
|
||||
|
||||
setup_go
|
||||
|
||||
fetch_and_deploy_gh_release "gluetun" "qdm12/gluetun" "tarball"
|
||||
|
||||
msg_info "Building Gluetun"
|
||||
cd /opt/gluetun
|
||||
$STD go mod download
|
||||
CGO_ENABLED=0 $STD go build -trimpath -ldflags="-s -w" -o /usr/local/bin/gluetun ./cmd/gluetun/
|
||||
msg_ok "Built Gluetun"
|
||||
|
||||
msg_info "Configuring Gluetun"
|
||||
mkdir -p /opt/gluetun-data
|
||||
touch /etc/alpine-release
|
||||
ln -sf /opt/gluetun-data /gluetun
|
||||
cat <<EOF >/opt/gluetun-data/.env
|
||||
VPN_SERVICE_PROVIDER=custom
|
||||
VPN_TYPE=openvpn
|
||||
OPENVPN_CUSTOM_CONFIG=/opt/gluetun-data/custom.ovpn
|
||||
OPENVPN_USER=
|
||||
OPENVPN_PASSWORD=
|
||||
OPENVPN_PROCESS_USER=root
|
||||
PUID=0
|
||||
PGID=0
|
||||
HTTP_CONTROL_SERVER_ADDRESS=:8000
|
||||
HTTPPROXY=off
|
||||
SHADOWSOCKS=off
|
||||
PPROF_ENABLED=no
|
||||
PPROF_BLOCK_PROFILE_RATE=0
|
||||
PPROF_MUTEX_PROFILE_RATE=0
|
||||
PPROF_HTTP_SERVER_ADDRESS=:6060
|
||||
FIREWALL_ENABLED_DISABLING_IT_SHOOTS_YOU_IN_YOUR_FOOT=on
|
||||
HEALTH_SERVER_ADDRESS=127.0.0.1:9999
|
||||
DNS_UPSTREAM_RESOLVERS=cloudflare
|
||||
LOG_LEVEL=info
|
||||
STORAGE_FILEPATH=/gluetun/servers.json
|
||||
PUBLICIP_FILE=/gluetun/ip
|
||||
VPN_PORT_FORWARDING_STATUS_FILE=/gluetun/forwarded_port
|
||||
TZ=UTC
|
||||
EOF
|
||||
msg_ok "Configured Gluetun"
|
||||
|
||||
msg_info "Creating Service"
|
||||
cat <<EOF >/etc/systemd/system/gluetun.service
|
||||
[Unit]
|
||||
Description=Gluetun VPN Client
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
WorkingDirectory=/opt/gluetun-data
|
||||
EnvironmentFile=/opt/gluetun-data/.env
|
||||
UnsetEnvironment=USER
|
||||
ExecStartPre=/bin/sh -c 'rm -f /etc/openvpn/target.ovpn'
|
||||
ExecStart=/usr/local/bin/gluetun
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
AmbientCapabilities=CAP_NET_ADMIN
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl enable -q --now gluetun
|
||||
msg_ok "Created Service"
|
||||
|
||||
motd_ssh
|
||||
customize
|
||||
cleanup_lxc
|
||||
@@ -14,10 +14,6 @@ network_check
|
||||
update_os
|
||||
setup_hwaccel
|
||||
|
||||
msg_info "Installing Dependencies"
|
||||
$STD apt install -y ffmpeg
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
USE_ORIGINAL_FILENAME="true" fetch_and_deploy_gh_release "go2rtc" "AlexxIT/go2rtc" "singlefile" "latest" "/opt/go2rtc" "go2rtc_linux_amd64"
|
||||
|
||||
msg_info "Creating Service"
|
||||
|
||||
@@ -32,13 +32,13 @@ if [ -d /dev/dri ]; then
|
||||
$STD apt install -y --no-install-recommends patchelf
|
||||
tmp_dir=$(mktemp -d)
|
||||
$STD pushd "$tmp_dir"
|
||||
curl_with_retry "https://raw.githubusercontent.com/immich-app/immich/refs/heads/main/machine-learning/Dockerfile" "Dockerfile"
|
||||
curl -fsSLO https://raw.githubusercontent.com/immich-app/immich/refs/heads/main/machine-learning/Dockerfile
|
||||
readarray -t INTEL_URLS < <(
|
||||
sed -n "/intel-[igc|opencl]/p" ./Dockerfile | awk '{print $3}'
|
||||
sed -n "/libigdgmm12/p" ./Dockerfile | awk '{print $3}'
|
||||
)
|
||||
for url in "${INTEL_URLS[@]}"; do
|
||||
curl_with_retry "$url" "$(basename "$url")"
|
||||
curl -fsSLO "$url"
|
||||
done
|
||||
$STD apt install -y ./libigdgmm12*.deb
|
||||
rm ./libigdgmm12*.deb
|
||||
@@ -154,10 +154,6 @@ sed -i "s/^#shared_preload.*/shared_preload_libraries = 'vchord.so'/" /etc/postg
|
||||
systemctl restart postgresql.service
|
||||
PG_DB_NAME="immich" PG_DB_USER="immich" PG_DB_GRANT_SUPERUSER="true" PG_DB_SKIP_ALTER_ROLE="true" setup_postgresql_db
|
||||
|
||||
msg_info "Installing GCC-13 (available as fallback compiler)"
|
||||
$STD apt install -y gcc-13 g++-13
|
||||
msg_ok "Installed GCC-13"
|
||||
|
||||
msg_warn "Compiling Custom Photo-processing Libraries (can take anywhere from 15min to 2h)"
|
||||
LD_LIBRARY_PATH=/usr/local/lib
|
||||
export LD_RUN_PATH=/usr/local/lib
|
||||
@@ -294,7 +290,7 @@ 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.6" "$SRC_DIR"
|
||||
PNPM_VERSION="$(jq -r '.packageManager | split("@")[1] | split("+")[0]' ${SRC_DIR}/package.json)"
|
||||
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)"
|
||||
@@ -344,36 +340,15 @@ cd "$SRC_DIR"/machine-learning
|
||||
$STD useradd -U -s /usr/sbin/nologin -r -M -d "$INSTALL_DIR" immich
|
||||
mkdir -p "$ML_DIR" && chown -R immich:immich "$INSTALL_DIR"
|
||||
export VIRTUAL_ENV="${ML_DIR}/ml-venv"
|
||||
export UV_HTTP_TIMEOUT=300
|
||||
if [[ -f ~/.openvino ]]; then
|
||||
ML_PYTHON="python3.13"
|
||||
msg_info "Pre-installing Python ${ML_PYTHON} for machine-learning"
|
||||
for attempt in $(seq 1 3); do
|
||||
$STD sudo --preserve-env=VIRTUAL_ENV -nu immich uv python install "${ML_PYTHON}" && break
|
||||
[[ $attempt -lt 3 ]] && msg_warn "Python download attempt $attempt failed, retrying..." && sleep 5
|
||||
done
|
||||
msg_ok "Pre-installed Python ${ML_PYTHON}"
|
||||
msg_info "Installing HW-accelerated machine-learning"
|
||||
$STD uv add --no-sync --optional openvino onnxruntime-openvino==1.24.1 --active -n -p "${ML_PYTHON}" --managed-python
|
||||
for attempt in $(seq 1 3); do
|
||||
$STD sudo --preserve-env=VIRTUAL_ENV,UV_HTTP_TIMEOUT -nu immich uv sync --extra openvino --no-dev --active --link-mode copy -n -p "${ML_PYTHON}" --managed-python && break
|
||||
[[ $attempt -lt 3 ]] && msg_warn "uv sync attempt $attempt failed, retrying..." && sleep 10
|
||||
done
|
||||
$STD uv add --no-sync --optional openvino onnxruntime-openvino==1.24.1 --active -n -p python3.13 --managed-python
|
||||
$STD sudo --preserve-env=VIRTUAL_ENV -nu immich uv sync --extra openvino --no-dev --active --link-mode copy -n -p python3.13 --managed-python
|
||||
patchelf --clear-execstack "${VIRTUAL_ENV}/lib/python3.13/site-packages/onnxruntime/capi/onnxruntime_pybind11_state.cpython-313-x86_64-linux-gnu.so"
|
||||
msg_ok "Installed HW-accelerated machine-learning"
|
||||
else
|
||||
ML_PYTHON="python3.11"
|
||||
msg_info "Pre-installing Python ${ML_PYTHON} for machine-learning"
|
||||
for attempt in $(seq 1 3); do
|
||||
$STD sudo --preserve-env=VIRTUAL_ENV -nu immich uv python install "${ML_PYTHON}" && break
|
||||
[[ $attempt -lt 3 ]] && msg_warn "Python download attempt $attempt failed, retrying..." && sleep 5
|
||||
done
|
||||
msg_ok "Pre-installed Python ${ML_PYTHON}"
|
||||
msg_info "Installing machine-learning"
|
||||
for attempt in $(seq 1 3); do
|
||||
$STD sudo --preserve-env=VIRTUAL_ENV,UV_HTTP_TIMEOUT -nu immich uv sync --extra cpu --no-dev --active --link-mode copy -n -p "${ML_PYTHON}" --managed-python && break
|
||||
[[ $attempt -lt 3 ]] && msg_warn "uv sync attempt $attempt failed, retrying..." && sleep 10
|
||||
done
|
||||
$STD sudo --preserve-env=VIRTUAL_ENV -nu immich uv sync --extra cpu --no-dev --active --link-mode copy -n -p python3.11 --managed-python
|
||||
msg_ok "Installed machine-learning"
|
||||
fi
|
||||
cd "$SRC_DIR"
|
||||
@@ -390,10 +365,10 @@ ln -s "$UPLOAD_DIR" "$ML_DIR"/upload
|
||||
|
||||
msg_info "Installing GeoNames data"
|
||||
cd "$GEO_DIR"
|
||||
curl_with_retry "https://download.geonames.org/export/dump/admin1CodesASCII.txt" "admin1CodesASCII.txt"
|
||||
curl_with_retry "https://download.geonames.org/export/dump/admin2Codes.txt" "admin2Codes.txt"
|
||||
curl_with_retry "https://download.geonames.org/export/dump/cities500.zip" "cities500.zip"
|
||||
curl_with_retry "https://raw.githubusercontent.com/nvkelso/natural-earth-vector/v5.1.2/geojson/ne_10m_admin_0_countries.geojson" "ne_10m_admin_0_countries.geojson"
|
||||
curl -fsSLZ -O "https://download.geonames.org/export/dump/admin1CodesASCII.txt" \
|
||||
-O "https://download.geonames.org/export/dump/admin2Codes.txt" \
|
||||
-O "https://download.geonames.org/export/dump/cities500.zip" \
|
||||
-O "https://raw.githubusercontent.com/nvkelso/natural-earth-vector/v5.1.2/geojson/ne_10m_admin_0_countries.geojson"
|
||||
unzip -q cities500.zip
|
||||
date --iso-8601=seconds | tr -d "\n" >geodata-date.txt
|
||||
rm cities500.zip
|
||||
|
||||
@@ -14,32 +14,40 @@ network_check
|
||||
update_os
|
||||
|
||||
setup_mariadb
|
||||
msg_info "Loading timezone data"
|
||||
mariadb-tzinfo-to-sql /usr/share/zoneinfo | mariadb mysql
|
||||
msg_ok "Loaded timezone data"
|
||||
MARIADB_DB_NAME="itsmng_db" MARIADB_DB_USER="itsmng" MARIADB_DB_EXTRA_GRANTS="GRANT SELECT ON \`mysql\`.\`time_zone_name\`" setup_mariadb_db
|
||||
|
||||
msg_info "Installing ITSM-NG"
|
||||
msg_info "Setting up database"
|
||||
DB_NAME=itsmng_db
|
||||
DB_USER=itsmng
|
||||
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
|
||||
mariadb-tzinfo-to-sql /usr/share/zoneinfo | mariadb mysql
|
||||
mariadb -u root -e "CREATE DATABASE $DB_NAME;"
|
||||
mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';"
|
||||
mariadb -u root -e "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost';"
|
||||
mariadb -u root -e "GRANT SELECT ON \`mysql\`.\`time_zone_name\` TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
|
||||
{
|
||||
echo "ITSM-NG Database Credentials"
|
||||
echo "Database: $DB_NAME"
|
||||
echo "Username: $DB_USER"
|
||||
echo "Password: $DB_PASS"
|
||||
} >>~/itsmng_db.creds
|
||||
msg_ok "Set up database"
|
||||
|
||||
msg_info "Setup ITSM-NG Repository"
|
||||
setup_deb822_repo \
|
||||
"itsm-ng" \
|
||||
"http://deb.itsm-ng.org/pubkey.gpg" \
|
||||
"http://deb.itsm-ng.org/$(get_os_info id)/" \
|
||||
"$(get_os_info codename)"
|
||||
msg_ok "Setup ITSM-NG Repository"
|
||||
|
||||
msg_info "Installing ITSM-NG"
|
||||
$STD apt install -y itsm-ng
|
||||
cd /usr/share/itsm-ng
|
||||
$STD php bin/console db:install --db-name="$MARIADB_DB_NAME" --db-user="$MARIADB_DB_USER" --db-password="$MARIADB_DB_PASS" --no-interaction
|
||||
$STD php bin/console db:install --db-name=$DB_NAME --db-user=$DB_USER --db-password=$DB_PASS --no-interaction
|
||||
$STD a2dissite 000-default.conf
|
||||
echo "* * * * * www-data php /usr/share/itsm-ng/front/cron.php" | crontab -
|
||||
echo "* * * * * php /usr/share/itsm-ng/front/cron.php" | crontab -
|
||||
msg_ok "Installed ITSM-NG"
|
||||
|
||||
msg_info "Setting permissions"
|
||||
chown -R www-data:www-data /var/lib/itsm-ng
|
||||
mkdir -p /usr/share/itsm-ng/css/palettes
|
||||
chown -R www-data:www-data /usr/share/itsm-ng/css
|
||||
chown -R www-data:www-data /usr/share/itsm-ng/css_compiled
|
||||
chown www-data:www-data /etc/itsm-ng/config_db.php
|
||||
msg_ok "Set permissions"
|
||||
|
||||
msg_info "Configuring PHP"
|
||||
PHP_VERSION=$(ls /etc/php/ | grep -E '^[0-9]+\.[0-9]+$' | head -n 1)
|
||||
PHP_INI="/etc/php/$PHP_VERSION/apache2/php.ini"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# Copyright (c) 2021-2026 tteck
|
||||
# Author: tteck (tteckster)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://jellyfin.org/
|
||||
|
||||
@@ -14,31 +14,31 @@ network_check
|
||||
update_os
|
||||
|
||||
msg_custom "ℹ️" "${GN}" "If NVIDIA GPU passthrough is detected, you'll be asked whether to install drivers in the container"
|
||||
setup_hwaccel
|
||||
|
||||
msg_info "Installing Dependencies"
|
||||
ensure_dependencies libjemalloc2
|
||||
msg_info "Installing Jellyfin"
|
||||
VERSION="$(awk -F'=' '/^VERSION_CODENAME=/{ print $NF }' /etc/os-release)"
|
||||
if ! dpkg -s libjemalloc2 >/dev/null 2>&1; then
|
||||
$STD apt install -y libjemalloc2
|
||||
fi
|
||||
if [[ ! -f /usr/lib/libjemalloc.so ]]; then
|
||||
ln -sf /usr/lib/x86_64-linux-gnu/libjemalloc.so.2 /usr/lib/libjemalloc.so
|
||||
fi
|
||||
msg_ok "Installed Dependencies"
|
||||
if [[ ! -d /etc/apt/keyrings ]]; then
|
||||
mkdir -p /etc/apt/keyrings
|
||||
fi
|
||||
curl -fsSL https://repo.jellyfin.org/jellyfin_team.gpg.key | gpg --dearmor --yes --output /etc/apt/keyrings/jellyfin.gpg
|
||||
cat <<EOF >/etc/apt/sources.list.d/jellyfin.sources
|
||||
Types: deb
|
||||
URIs: https://repo.jellyfin.org/${PCT_OSTYPE}
|
||||
Suites: ${VERSION}
|
||||
Components: main
|
||||
Architectures: amd64
|
||||
Signed-By: /etc/apt/keyrings/jellyfin.gpg
|
||||
EOF
|
||||
|
||||
msg_info "Setting up Jellyfin Repository"
|
||||
setup_deb822_repo \
|
||||
"jellyfin" \
|
||||
"https://repo.jellyfin.org/jellyfin_team.gpg.key" \
|
||||
"https://repo.jellyfin.org/$(get_os_info id)" \
|
||||
"$(get_os_info codename)"
|
||||
msg_ok "Set up Jellyfin Repository"
|
||||
|
||||
msg_info "Installing Jellyfin"
|
||||
$STD apt install -y jellyfin jellyfin-ffmpeg7
|
||||
ln -sf /usr/lib/jellyfin-ffmpeg/ffmpeg /usr/bin/ffmpeg
|
||||
ln -sf /usr/lib/jellyfin-ffmpeg/ffprobe /usr/bin/ffprobe
|
||||
msg_ok "Installed Jellyfin"
|
||||
|
||||
setup_hwaccel "jellyfin"
|
||||
|
||||
msg_info "Configuring Jellyfin"
|
||||
$STD apt update
|
||||
$STD apt install -y jellyfin
|
||||
# Configure log rotation to prevent disk fill (keeps fail2ban compatibility) (PR: #1690 / Issue: #11224)
|
||||
cat <<EOF >/etc/logrotate.d/jellyfin
|
||||
/var/log/jellyfin/*.log {
|
||||
@@ -55,7 +55,12 @@ EOF
|
||||
chown -R jellyfin:adm /etc/jellyfin
|
||||
sleep 10
|
||||
systemctl restart jellyfin
|
||||
msg_ok "Configured Jellyfin"
|
||||
if [[ "$CTTYPE" == "0" ]]; then
|
||||
sed -i -e 's/^ssl-cert:x:104:$/render:x:104:root,jellyfin/' -e 's/^render:x:108:root,jellyfin$/ssl-cert:x:108:/' /etc/group
|
||||
else
|
||||
sed -i -e 's/^ssl-cert:x:104:$/render:x:104:jellyfin/' -e 's/^render:x:108:jellyfin$/ssl-cert:x:108:/' /etc/group
|
||||
fi
|
||||
msg_ok "Installed Jellyfin"
|
||||
|
||||
motd_ssh
|
||||
customize
|
||||
|
||||
@@ -42,6 +42,8 @@ EOF
|
||||
$STD apt update
|
||||
msg_ok "Set up Intel® Repositories"
|
||||
|
||||
setup_hwaccel
|
||||
|
||||
msg_info "Installing Intel® Level Zero"
|
||||
# Debian 13+ has newer Level Zero packages in system repos that conflict with Intel repo packages
|
||||
if is_debian && [[ "$(get_os_version_major)" -ge 13 ]]; then
|
||||
@@ -87,11 +89,11 @@ msg_info "Creating ollama User and Group"
|
||||
if ! id ollama >/dev/null 2>&1; then
|
||||
useradd -r -s /usr/sbin/nologin -U -m -d /usr/share/ollama ollama
|
||||
fi
|
||||
$STD usermod -aG render ollama || true
|
||||
$STD usermod -aG video ollama || true
|
||||
$STD usermod -aG ollama $(id -u -n)
|
||||
msg_ok "Created ollama User and adjusted Groups"
|
||||
|
||||
setup_hwaccel "ollama"
|
||||
|
||||
msg_info "Creating Service"
|
||||
cat <<EOF >/etc/systemd/system/ollama.service
|
||||
[Unit]
|
||||
|
||||
@@ -13,6 +13,8 @@ setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
|
||||
setup_hwaccel
|
||||
|
||||
msg_info "Setting Up Plex Media Server Repository"
|
||||
setup_deb822_repo \
|
||||
"plexmediaserver" \
|
||||
@@ -24,10 +26,13 @@ msg_ok "Set Up Plex Media Server Repository"
|
||||
|
||||
msg_info "Installing Plex Media Server"
|
||||
$STD apt install -y plexmediaserver
|
||||
if [[ "$CTTYPE" == "0" ]]; then
|
||||
sed -i -e 's/^ssl-cert:x:104:plex$/render:x:104:root,plex/' -e 's/^render:x:108:root$/ssl-cert:x:108:plex/' /etc/group
|
||||
else
|
||||
sed -i -e 's/^ssl-cert:x:104:plex$/render:x:104:plex/' -e 's/^render:x:108:$/ssl-cert:x:108:/' /etc/group
|
||||
fi
|
||||
msg_ok "Installed Plex Media Server"
|
||||
|
||||
setup_hwaccel "plex"
|
||||
|
||||
motd_ssh
|
||||
customize
|
||||
cleanup_lxc
|
||||
|
||||
@@ -45,58 +45,32 @@ systemctl enable -q --now podman.socket
|
||||
echo -e 'unqualified-search-registries=["docker.io"]' >>/etc/containers/registries.conf
|
||||
msg_ok "Installed Podman"
|
||||
|
||||
mkdir -p /etc/containers/systemd
|
||||
|
||||
read -r -p "${TAB3}Would you like to add Portainer? <y/N> " prompt
|
||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
|
||||
msg_info "Installing Portainer $PORTAINER_LATEST_VERSION"
|
||||
podman volume create portainer_data >/dev/null
|
||||
cat <<EOF >/etc/containers/systemd/portainer.container
|
||||
[Unit]
|
||||
Description=Portainer Container
|
||||
After=network-online.target
|
||||
|
||||
[Container]
|
||||
Image=docker.io/portainer/portainer-ce:latest
|
||||
ContainerName=portainer
|
||||
PublishPort=8000:8000
|
||||
PublishPort=9443:9443
|
||||
Volume=/run/podman/podman.sock:/var/run/docker.sock
|
||||
Volume=portainer_data:/data
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target multi-user.target
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
$STD systemctl start portainer
|
||||
$STD podman run -d \
|
||||
-p 8000:8000 \
|
||||
-p 9443:9443 \
|
||||
--name=portainer \
|
||||
--restart=always \
|
||||
-v /run/podman/podman.sock:/var/run/docker.sock \
|
||||
-v portainer_data:/data \
|
||||
portainer/portainer-ce:latest
|
||||
msg_ok "Installed Portainer $PORTAINER_LATEST_VERSION"
|
||||
else
|
||||
read -r -p "${TAB3}Would you like to add the Portainer Agent? <y/N> " prompt
|
||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
|
||||
msg_info "Installing Portainer agent $PORTAINER_AGENT_LATEST_VERSION"
|
||||
cat <<EOF >/etc/containers/systemd/portainer-agent.container
|
||||
[Unit]
|
||||
Description=Portainer Agent Container
|
||||
After=network-online.target
|
||||
|
||||
[Container]
|
||||
Image=docker.io/portainer/agent:latest
|
||||
ContainerName=portainer_agent
|
||||
PublishPort=9001:9001
|
||||
Volume=/run/podman/podman.sock:/var/run/docker.sock
|
||||
Volume=/var/lib/containers/storage/volumes:/var/lib/docker/volumes
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target multi-user.target
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
$STD systemctl start portainer-agent
|
||||
podman volume create temp >/dev/null
|
||||
podman volume remove temp >/dev/null
|
||||
$STD podman run -d \
|
||||
-p 9001:9001 \
|
||||
--name portainer_agent \
|
||||
--restart=always \
|
||||
-v /run/podman/podman.sock:/var/run/docker.sock \
|
||||
-v /var/lib/containers/storage/volumes:/var/lib/docker/volumes \
|
||||
portainer/agent
|
||||
msg_ok "Installed Portainer Agent $PORTAINER_AGENT_LATEST_VERSION"
|
||||
fi
|
||||
fi
|
||||
@@ -107,29 +81,19 @@ msg_ok "Pulled Home Assistant Image"
|
||||
|
||||
msg_info "Installing Home Assistant"
|
||||
$STD podman volume create hass_config
|
||||
cat <<EOF >/etc/containers/systemd/homeassistant.container
|
||||
[Unit]
|
||||
Description=Home Assistant Container
|
||||
After=network-online.target
|
||||
|
||||
[Container]
|
||||
Image=docker.io/homeassistant/home-assistant:stable
|
||||
ContainerName=homeassistant
|
||||
Volume=/dev:/dev
|
||||
Volume=hass_config:/config
|
||||
Volume=/etc/localtime:/etc/localtime:ro
|
||||
Volume=/etc/timezone:/etc/timezone:ro
|
||||
Network=host
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
TimeoutStartSec=300
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target multi-user.target
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
$STD systemctl start homeassistant
|
||||
$STD podman run -d \
|
||||
--name homeassistant \
|
||||
--restart unless-stopped \
|
||||
-v /dev:/dev \
|
||||
-v hass_config:/config \
|
||||
-v /etc/localtime:/etc/localtime:ro \
|
||||
-v /etc/timezone:/etc/timezone:ro \
|
||||
--net=host \
|
||||
homeassistant/home-assistant:stable
|
||||
podman generate systemd \
|
||||
--new --name homeassistant \
|
||||
>/etc/systemd/system/homeassistant.service
|
||||
systemctl enable -q --now homeassistant
|
||||
msg_ok "Installed Home Assistant"
|
||||
|
||||
motd_ssh
|
||||
|
||||
@@ -45,58 +45,32 @@ systemctl enable -q --now podman.socket
|
||||
echo -e 'unqualified-search-registries=["docker.io"]' >>/etc/containers/registries.conf
|
||||
msg_ok "Installed Podman"
|
||||
|
||||
mkdir -p /etc/containers/systemd
|
||||
|
||||
read -r -p "${TAB3}Would you like to add Portainer? <y/N> " prompt
|
||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
|
||||
msg_info "Installing Portainer $PORTAINER_LATEST_VERSION"
|
||||
podman volume create portainer_data >/dev/null
|
||||
cat <<EOF >/etc/containers/systemd/portainer.container
|
||||
[Unit]
|
||||
Description=Portainer Container
|
||||
After=network-online.target
|
||||
|
||||
[Container]
|
||||
Image=docker.io/portainer/portainer-ce:latest
|
||||
ContainerName=portainer
|
||||
PublishPort=8000:8000
|
||||
PublishPort=9443:9443
|
||||
Volume=/run/podman/podman.sock:/var/run/docker.sock
|
||||
Volume=portainer_data:/data
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target multi-user.target
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
$STD systemctl start portainer
|
||||
$STD podman run -d \
|
||||
-p 8000:8000 \
|
||||
-p 9443:9443 \
|
||||
--name=portainer \
|
||||
--restart=always \
|
||||
-v /run/podman/podman.sock:/var/run/docker.sock \
|
||||
-v portainer_data:/data \
|
||||
portainer/portainer-ce:latest
|
||||
msg_ok "Installed Portainer $PORTAINER_LATEST_VERSION"
|
||||
else
|
||||
read -r -p "${TAB3}Would you like to add the Portainer Agent? <y/N> " prompt
|
||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
|
||||
msg_info "Installing Portainer agent $PORTAINER_AGENT_LATEST_VERSION"
|
||||
cat <<EOF >/etc/containers/systemd/portainer-agent.container
|
||||
[Unit]
|
||||
Description=Portainer Agent Container
|
||||
After=network-online.target
|
||||
|
||||
[Container]
|
||||
Image=docker.io/portainer/agent:latest
|
||||
ContainerName=portainer_agent
|
||||
PublishPort=9001:9001
|
||||
Volume=/run/podman/podman.sock:/var/run/docker.sock
|
||||
Volume=/var/lib/containers/storage/volumes:/var/lib/docker/volumes
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target multi-user.target
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
$STD systemctl start portainer-agent
|
||||
podman volume create temp >/dev/null
|
||||
podman volume remove temp >/dev/null
|
||||
$STD podman run -d \
|
||||
-p 9001:9001 \
|
||||
--name portainer_agent \
|
||||
--restart=always \
|
||||
-v /run/podman/podman.sock:/var/run/docker.sock \
|
||||
-v /var/lib/containers/storage/volumes:/var/lib/docker/volumes \
|
||||
portainer/agent
|
||||
msg_ok "Installed Portainer Agent $PORTAINER_AGENT_LATEST_VERSION"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -44,7 +44,7 @@ msg_ok "Configured RabbitMQ"
|
||||
|
||||
USE_ORIGINAL_FILENAME="true" fetch_and_deploy_gh_release "reitti" "dedicatedcode/reitti" "singlefile" "latest" "/opt/reitti" "reitti-app.jar"
|
||||
mv /opt/reitti/reitti-*.jar /opt/reitti/reitti.jar
|
||||
USE_ORIGINAL_FILENAME="true" fetch_and_deploy_gh_release "photon" "komoot/photon" "singlefile" "latest" "/opt/photon" "photon-*.jar"
|
||||
USE_ORIGINAL_FILENAME="true" fetch_and_deploy_gh_release "photon" "komoot/photon" "singlefile" "latest" "/opt/photon" "photon-0*.jar"
|
||||
mv /opt/photon/photon-*.jar /opt/photon/photon.jar
|
||||
|
||||
msg_info "Installing Nginx Tile Cache"
|
||||
|
||||
@@ -14,9 +14,7 @@ network_check
|
||||
update_os
|
||||
|
||||
msg_info "Installing Dependencies"
|
||||
$STD apt install -y \
|
||||
build-essential \
|
||||
python3-setuptools
|
||||
$STD apt-get install -y build-essential
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
fetch_and_deploy_gh_release "seerr" "seerr-team/seerr" "tarball"
|
||||
|
||||
@@ -47,7 +47,7 @@ msg_ok "Configured Sparky Fitness"
|
||||
|
||||
msg_info "Building Backend"
|
||||
cd /opt/sparkyfitness/SparkyFitnessServer
|
||||
$STD pnpm install
|
||||
$STD npm install
|
||||
msg_ok "Built Backend"
|
||||
|
||||
msg_info "Building Frontend (Patience)"
|
||||
@@ -69,7 +69,7 @@ Requires=postgresql.service
|
||||
Type=simple
|
||||
WorkingDirectory=/opt/sparkyfitness/SparkyFitnessServer
|
||||
EnvironmentFile=/etc/sparkyfitness/.env
|
||||
ExecStart=/opt/sparkyfitness/SparkyFitnessServer/node_modules/.bin/tsx SparkyFitnessServer.js
|
||||
ExecStart=/usr/bin/node SparkyFitnessServer.js
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: johanngrobe
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/oss-apps/split-pro
|
||||
|
||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||
color
|
||||
verb_ip6
|
||||
catch_errors
|
||||
setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
|
||||
NODE_VERSION="22" NODE_MODULE="pnpm" setup_nodejs
|
||||
PG_VERSION="17" PG_MODULES="cron" setup_postgresql
|
||||
|
||||
msg_info "Installing Dependencies"
|
||||
$STD apt install -y openssl
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
PG_DB_NAME="splitpro" PG_DB_USER="splitpro" PG_DB_EXTENSIONS="pg_cron" setup_postgresql_db
|
||||
fetch_and_deploy_gh_release "split-pro" "oss-apps/split-pro" "tarball"
|
||||
|
||||
msg_info "Installing Dependencies"
|
||||
cd /opt/split-pro
|
||||
$STD pnpm install --frozen-lockfile
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
msg_info "Building Split Pro"
|
||||
cd /opt/split-pro
|
||||
mkdir -p /opt/split-pro_data/uploads
|
||||
ln -sf /opt/split-pro_data/uploads /opt/split-pro/uploads
|
||||
NEXTAUTH_SECRET=$(openssl rand -base64 32)
|
||||
cp .env.example .env
|
||||
sed -i "s|^DATABASE_URL=.*|DATABASE_URL=\"postgresql://${PG_DB_USER}:${PG_DB_PASS}@localhost:5432/${PG_DB_NAME}\"|" .env
|
||||
sed -i "s|^NEXTAUTH_SECRET=.*|NEXTAUTH_SECRET=\"${NEXTAUTH_SECRET}\"|" .env
|
||||
sed -i "s|^NEXTAUTH_URL=.*|NEXTAUTH_URL=\"http://${LOCAL_IP}:3000\"|" .env
|
||||
sed -i "s|^NEXTAUTH_URL_INTERNAL=.*|NEXTAUTH_URL_INTERNAL=\"http://localhost:3000\"|" .env
|
||||
sed -i "/^POSTGRES_CONTAINER_NAME=/d" .env
|
||||
sed -i "/^POSTGRES_USER=/d" .env
|
||||
sed -i "/^POSTGRES_PASSWORD=/d" .env
|
||||
sed -i "/^POSTGRES_DB=/d" .env
|
||||
sed -i "/^POSTGRES_PORT=/d" .env
|
||||
$STD pnpm build
|
||||
$STD pnpm exec prisma migrate deploy
|
||||
msg_ok "Built Split Pro"
|
||||
|
||||
msg_info "Creating Service"
|
||||
cat <<EOF >/etc/systemd/system/split-pro.service
|
||||
[Unit]
|
||||
Description=Split Pro
|
||||
After=network.target postgresql.service
|
||||
Requires=postgresql.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
WorkingDirectory=/opt/split-pro
|
||||
EnvironmentFile=/opt/split-pro/.env
|
||||
ExecStart=/usr/bin/pnpm start
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl enable -q --now split-pro
|
||||
msg_ok "Created Service"
|
||||
|
||||
motd_ssh
|
||||
customize
|
||||
cleanup_lxc
|
||||
@@ -20,16 +20,12 @@ msg_ok "Installed Dependencies"
|
||||
msg_info "Installing Tdarr"
|
||||
mkdir -p /opt/tdarr
|
||||
cd /opt/tdarr
|
||||
RELEASE=$(curl_with_retry "https://f000.backblazeb2.com/file/tdarrs/versions.json" "-" | grep -oP '(?<="Tdarr_Updater": ")[^"]+' | grep linux_x64 | head -n 1)
|
||||
curl_with_retry "$RELEASE" "Tdarr_Updater.zip"
|
||||
RELEASE=$(curl -fsSL https://f000.backblazeb2.com/file/tdarrs/versions.json | grep -oP '(?<="Tdarr_Updater": ")[^"]+' | grep linux_x64 | head -n 1)
|
||||
curl -fsSL "$RELEASE" -o Tdarr_Updater.zip
|
||||
$STD unzip Tdarr_Updater.zip
|
||||
chmod +x Tdarr_Updater
|
||||
$STD ./Tdarr_Updater
|
||||
rm -rf /opt/tdarr/Tdarr_Updater.zip
|
||||
[[ -f /opt/tdarr/Tdarr_Server/Tdarr_Server ]] || {
|
||||
msg_error "Tdarr_Updater failed — tdarr.io may be blocked by local DNS"
|
||||
exit 250
|
||||
}
|
||||
msg_ok "Installed Tdarr"
|
||||
|
||||
setup_hwaccel
|
||||
|
||||
@@ -19,41 +19,9 @@ $STD apt install -y \
|
||||
python3 \
|
||||
nginx \
|
||||
openssl \
|
||||
gettext-base \
|
||||
libcairo2-dev \
|
||||
libjpeg62-turbo-dev \
|
||||
libpng-dev \
|
||||
libtool-bin \
|
||||
uuid-dev \
|
||||
libvncserver-dev \
|
||||
freerdp3-dev \
|
||||
libssh2-1-dev \
|
||||
libtelnet-dev \
|
||||
libwebsockets-dev \
|
||||
libpulse-dev \
|
||||
libvorbis-dev \
|
||||
libwebp-dev \
|
||||
libssl-dev \
|
||||
libpango1.0-dev \
|
||||
libswscale-dev \
|
||||
libavcodec-dev \
|
||||
libavutil-dev \
|
||||
libavformat-dev
|
||||
gettext-base
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
msg_info "Building Guacamole Server (guacd)"
|
||||
fetch_and_deploy_gh_tag "guacd" "apache/guacamole-server" "latest" "/opt/guacamole-server"
|
||||
cd /opt/guacamole-server
|
||||
export CPPFLAGS="-Wno-error=deprecated-declarations"
|
||||
$STD autoreconf -fi
|
||||
$STD ./configure --with-init-dir=/etc/init.d --enable-allow-freerdp-snapshots
|
||||
$STD make
|
||||
$STD make install
|
||||
$STD ldconfig
|
||||
cd /opt
|
||||
rm -rf /opt/guacamole-server
|
||||
msg_ok "Built Guacamole Server (guacd)"
|
||||
|
||||
NODE_VERSION="22" setup_nodejs
|
||||
fetch_and_deploy_gh_release "termix" "Termix-SSH/Termix"
|
||||
|
||||
@@ -106,46 +74,17 @@ systemctl reload nginx
|
||||
msg_ok "Configured Nginx"
|
||||
|
||||
msg_info "Creating Service"
|
||||
mkdir -p /etc/guacamole
|
||||
cat <<EOF >/etc/guacamole/guacd.conf
|
||||
[server]
|
||||
bind_host = 127.0.0.1
|
||||
bind_port = 4822
|
||||
EOF
|
||||
|
||||
cat <<EOF >/opt/termix/.env
|
||||
NODE_ENV=production
|
||||
DATA_DIR=/opt/termix/data
|
||||
GUACD_HOST=127.0.0.1
|
||||
GUACD_PORT=4822
|
||||
EOF
|
||||
|
||||
cat <<EOF >/etc/systemd/system/guacd.service
|
||||
[Unit]
|
||||
Description=Guacamole Proxy Daemon (guacd)
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/local/sbin/guacd -f -b 127.0.0.1 -l 4822
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
cat <<EOF >/etc/systemd/system/termix.service
|
||||
[Unit]
|
||||
Description=Termix Backend
|
||||
After=network.target guacd.service
|
||||
Wants=guacd.service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
WorkingDirectory=/opt/termix
|
||||
EnvironmentFile=/opt/termix/.env
|
||||
Environment=NODE_ENV=production
|
||||
Environment=DATA_DIR=/opt/termix/data
|
||||
ExecStart=/usr/bin/node /opt/termix/dist/backend/backend/starter.js
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
@@ -153,7 +92,7 @@ RestartSec=5
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl enable -q --now guacd termix
|
||||
systemctl enable -q --now termix
|
||||
msg_ok "Created Service"
|
||||
|
||||
motd_ssh
|
||||
|
||||
@@ -30,7 +30,7 @@ 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 --frozen-lockfile
|
||||
$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)
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/FuzzyGrim/Yamtrack
|
||||
|
||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||
color
|
||||
verb_ip6
|
||||
catch_errors
|
||||
setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
|
||||
msg_info "Installing Dependencies"
|
||||
$STD apt install -y \
|
||||
nginx \
|
||||
redis-server
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
PG_VERSION="16" setup_postgresql
|
||||
PG_DB_NAME="yamtrack" PG_DB_USER="yamtrack" setup_postgresql_db
|
||||
PYTHON_VERSION="3.12" setup_uv
|
||||
|
||||
fetch_and_deploy_gh_release "yamtrack" "FuzzyGrim/Yamtrack" "tarball"
|
||||
|
||||
msg_info "Installing Python Dependencies"
|
||||
cd /opt/yamtrack
|
||||
$STD uv venv .venv
|
||||
$STD uv pip install --no-cache-dir -r requirements.txt
|
||||
msg_ok "Installed Python Dependencies"
|
||||
|
||||
msg_info "Configuring Yamtrack"
|
||||
SECRET=$(openssl rand -hex 32)
|
||||
cat <<EOF >/opt/yamtrack/src/.env
|
||||
SECRET=${SECRET}
|
||||
DB_HOST=localhost
|
||||
DB_NAME=${PG_DB_NAME}
|
||||
DB_USER=${PG_DB_USER}
|
||||
DB_PASSWORD=${PG_DB_PASS}
|
||||
DB_PORT=5432
|
||||
REDIS_URL=redis://localhost:6379
|
||||
URLS=http://${LOCAL_IP}:8000
|
||||
EOF
|
||||
|
||||
cd /opt/yamtrack/src
|
||||
$STD /opt/yamtrack/.venv/bin/python manage.py migrate
|
||||
$STD /opt/yamtrack/.venv/bin/python manage.py collectstatic --noinput
|
||||
msg_ok "Configured Yamtrack"
|
||||
|
||||
msg_info "Configuring Nginx"
|
||||
rm -f /etc/nginx/sites-enabled/default /etc/nginx/sites-available/default
|
||||
cp /opt/yamtrack/nginx.conf /etc/nginx/nginx.conf
|
||||
sed -i 's|user abc;|user www-data;|' /etc/nginx/nginx.conf
|
||||
sed -i 's|pid /tmp/nginx.pid;|pid /run/nginx.pid;|' /etc/nginx/nginx.conf
|
||||
sed -i 's|/yamtrack/staticfiles/|/opt/yamtrack/src/staticfiles/|' /etc/nginx/nginx.conf
|
||||
sed -i 's|error_log /dev/stderr|error_log /var/log/nginx/error.log|' /etc/nginx/nginx.conf
|
||||
sed -i 's|access_log /dev/stdout|access_log /var/log/nginx/access.log|' /etc/nginx/nginx.conf
|
||||
$STD nginx -t
|
||||
systemctl enable -q nginx
|
||||
$STD systemctl restart nginx
|
||||
msg_ok "Configured Nginx"
|
||||
|
||||
msg_info "Creating Services"
|
||||
cat <<EOF >/etc/systemd/system/yamtrack.service
|
||||
[Unit]
|
||||
Description=Yamtrack Gunicorn
|
||||
After=network.target postgresql.service redis-server.service
|
||||
Requires=postgresql.service redis-server.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/opt/yamtrack/src
|
||||
ExecStart=/opt/yamtrack/.venv/bin/gunicorn config.wsgi:application -b 127.0.0.1:8001 -w 2 --timeout 120
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
cat <<EOF >/etc/systemd/system/yamtrack-celery.service
|
||||
[Unit]
|
||||
Description=Yamtrack Celery Worker
|
||||
After=network.target postgresql.service redis-server.service yamtrack.service
|
||||
Requires=postgresql.service redis-server.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/opt/yamtrack/src
|
||||
ExecStart=/opt/yamtrack/.venv/bin/celery -A config worker --beat --scheduler django --loglevel INFO
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
systemctl enable -q --now redis-server yamtrack yamtrack-celery
|
||||
msg_ok "Created Services"
|
||||
|
||||
motd_ssh
|
||||
customize
|
||||
cleanup_lxc
|
||||
416
misc/tools.func
416
misc/tools.func
@@ -105,13 +105,11 @@ curl_with_retry() {
|
||||
fi
|
||||
fi
|
||||
|
||||
debug_log "curl attempt $attempt failed (timeout=${timeout}s), waiting ${backoff}s before retry..."
|
||||
debug_log "curl attempt $attempt failed, waiting ${backoff}s before retry..."
|
||||
sleep "$backoff"
|
||||
# Exponential backoff: 1, 2, 4, 8... capped at 30s
|
||||
backoff=$((backoff * 2))
|
||||
((backoff > 30)) && backoff=30
|
||||
# Double --max-time on each retry so slow connections can finish
|
||||
timeout=$((timeout * 2))
|
||||
((attempt++))
|
||||
done
|
||||
|
||||
@@ -174,10 +172,8 @@ curl_api_with_retry() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
debug_log "curl API attempt $attempt failed (HTTP $http_code, timeout=${timeout}s), waiting ${attempt}s..."
|
||||
debug_log "curl API attempt $attempt failed (HTTP $http_code), waiting ${attempt}s..."
|
||||
sleep "$attempt"
|
||||
# Double --max-time on each retry so slow connections can finish
|
||||
timeout=$((timeout * 2))
|
||||
((attempt++))
|
||||
done
|
||||
|
||||
@@ -1979,47 +1975,6 @@ extract_version_from_json() {
|
||||
fi
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Get latest GitHub tag (for repos that only publish tags, not releases).
|
||||
#
|
||||
# Usage:
|
||||
# get_latest_gh_tag "owner/repo" [prefix]
|
||||
#
|
||||
# Arguments:
|
||||
# $1 - GitHub repo (owner/repo)
|
||||
# $2 - Optional prefix filter (e.g., "v" to only match tags starting with "v")
|
||||
#
|
||||
# Returns:
|
||||
# Latest tag name (stdout), or returns 1 on failure
|
||||
# ------------------------------------------------------------------------------
|
||||
get_latest_gh_tag() {
|
||||
local repo="$1"
|
||||
local prefix="${2:-}"
|
||||
local temp_file
|
||||
temp_file=$(mktemp)
|
||||
|
||||
if ! github_api_call "https://api.github.com/repos/${repo}/tags?per_page=50" "$temp_file"; then
|
||||
rm -f "$temp_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local tag=""
|
||||
if [[ -n "$prefix" ]]; then
|
||||
tag=$(jq -r --arg p "$prefix" '[.[] | select(.name | startswith($p))][0].name // empty' "$temp_file")
|
||||
else
|
||||
tag=$(jq -r '.[0].name // empty' "$temp_file")
|
||||
fi
|
||||
|
||||
rm -f "$temp_file"
|
||||
|
||||
if [[ -z "$tag" ]]; then
|
||||
msg_error "No tags found for ${repo}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$tag"
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Get latest GitHub release version with fallback to tags
|
||||
# Usage: get_latest_github_release "owner/repo" [strip_v] [include_prerelease]
|
||||
@@ -2118,129 +2073,101 @@ verify_gpg_fingerprint() {
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Fetches and deploys a GitHub tag-based source tarball.
|
||||
# Get latest GitHub tag for a repository.
|
||||
#
|
||||
# Description:
|
||||
# - Downloads the source tarball for a given tag from GitHub
|
||||
# - Extracts to the target directory
|
||||
# - Writes the version to ~/.<app>
|
||||
# - Queries the GitHub API for tags (not releases)
|
||||
# - Useful for repos that only create tags, not full releases
|
||||
# - Supports optional prefix filter and version-only extraction
|
||||
# - Returns the latest tag name (printed to stdout)
|
||||
#
|
||||
# Usage:
|
||||
# fetch_and_deploy_gh_tag "guacd" "apache/guacamole-server"
|
||||
# fetch_and_deploy_gh_tag "guacd" "apache/guacamole-server" "latest" "/opt/guacamole-server"
|
||||
# MONGO_VERSION=$(get_latest_gh_tag "mongodb/mongo-tools")
|
||||
# LATEST=$(get_latest_gh_tag "owner/repo" "v") # only tags starting with "v"
|
||||
# LATEST=$(get_latest_gh_tag "owner/repo" "" "true") # strip leading "v"
|
||||
#
|
||||
# Arguments:
|
||||
# $1 - App name (used for version file ~/.<app>)
|
||||
# $2 - GitHub repo (owner/repo)
|
||||
# $3 - Tag version (default: "latest" → auto-detect via get_latest_gh_tag)
|
||||
# $4 - Target directory (default: /opt/$app)
|
||||
# $1 - GitHub repo (owner/repo)
|
||||
# $2 - Tag prefix filter (optional, e.g. "v" or "100.")
|
||||
# $3 - Strip prefix from result (optional, "true" to strip $2 prefix)
|
||||
#
|
||||
# Returns:
|
||||
# 0 on success (tag printed to stdout), 1 on failure
|
||||
#
|
||||
# Notes:
|
||||
# - Supports CLEAN_INSTALL=1 to wipe target before extracting
|
||||
# - For repos that only publish tags, not GitHub Releases
|
||||
# - Skips tags containing "rc", "alpha", "beta", "dev", "test"
|
||||
# - Sorts by version number (sort -V) to find the latest
|
||||
# - Respects GITHUB_TOKEN for rate limiting
|
||||
# ------------------------------------------------------------------------------
|
||||
fetch_and_deploy_gh_tag() {
|
||||
local app="$1"
|
||||
local repo="$2"
|
||||
local version="${3:-latest}"
|
||||
local target="${4:-/opt/$app}"
|
||||
local app_lc=""
|
||||
app_lc="$(echo "${app,,}" | tr -d ' ')"
|
||||
local version_file="$HOME/.${app_lc}"
|
||||
get_latest_gh_tag() {
|
||||
local repo="$1"
|
||||
local prefix="${2:-}"
|
||||
local strip_prefix="${3:-false}"
|
||||
|
||||
if [[ "$version" == "latest" ]]; then
|
||||
version=$(get_latest_gh_tag "$repo") || {
|
||||
msg_error "Failed to determine latest tag for ${repo}"
|
||||
return 1
|
||||
}
|
||||
fi
|
||||
local header_args=()
|
||||
[[ -n "${GITHUB_TOKEN:-}" ]] && header_args=(-H "Authorization: Bearer $GITHUB_TOKEN")
|
||||
|
||||
local current_version=""
|
||||
[[ -f "$version_file" ]] && current_version=$(<"$version_file")
|
||||
local http_code=""
|
||||
http_code=$(curl -sSL --max-time 20 -w "%{http_code}" -o /tmp/gh_tags.json \
|
||||
-H 'Accept: application/vnd.github+json' \
|
||||
-H 'X-GitHub-Api-Version: 2022-11-28' \
|
||||
"${header_args[@]}" \
|
||||
"https://api.github.com/repos/${repo}/tags?per_page=100" 2>/dev/null) || true
|
||||
|
||||
if [[ "$current_version" == "$version" ]]; then
|
||||
msg_ok "$app is already up-to-date ($version)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local tmpdir
|
||||
tmpdir=$(mktemp -d) || return 1
|
||||
local tarball_url="https://github.com/${repo}/archive/refs/tags/${version}.tar.gz"
|
||||
local filename="${app_lc}-${version}.tar.gz"
|
||||
|
||||
msg_info "Fetching GitHub tag: ${app} (${version})"
|
||||
|
||||
download_file "$tarball_url" "$tmpdir/$filename" || {
|
||||
msg_error "Download failed: $tarball_url"
|
||||
rm -rf "$tmpdir"
|
||||
if [[ "$http_code" == "401" ]]; then
|
||||
msg_error "GitHub API authentication failed (HTTP 401)."
|
||||
if [[ -n "${GITHUB_TOKEN:-}" ]]; then
|
||||
msg_error "Your GITHUB_TOKEN appears to be invalid or expired."
|
||||
else
|
||||
msg_error "The repository may require authentication. Try: export GITHUB_TOKEN=\"ghp_your_token\""
|
||||
fi
|
||||
rm -f /tmp/gh_tags.json
|
||||
return 1
|
||||
}
|
||||
|
||||
mkdir -p "$target"
|
||||
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
|
||||
rm -rf "${target:?}/"*
|
||||
fi
|
||||
|
||||
tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || {
|
||||
msg_error "Failed to extract tarball"
|
||||
rm -rf "$tmpdir"
|
||||
if [[ "$http_code" == "403" ]]; then
|
||||
msg_error "GitHub API rate limit exceeded (HTTP 403)."
|
||||
msg_error "To increase the limit, export a GitHub token before running the script:"
|
||||
msg_error " export GITHUB_TOKEN=\"ghp_your_token_here\""
|
||||
rm -f /tmp/gh_tags.json
|
||||
return 1
|
||||
}
|
||||
fi
|
||||
|
||||
local unpack_dir
|
||||
unpack_dir=$(find "$tmpdir" -mindepth 1 -maxdepth 1 -type d | head -n1)
|
||||
if [[ "$http_code" == "000" || -z "$http_code" ]]; then
|
||||
msg_error "GitHub API connection failed (no response)."
|
||||
msg_error "Check your network/DNS: curl -sSL https://api.github.com/rate_limit"
|
||||
rm -f /tmp/gh_tags.json
|
||||
return 1
|
||||
fi
|
||||
|
||||
shopt -s dotglob nullglob
|
||||
cp -r "$unpack_dir"/* "$target/"
|
||||
shopt -u dotglob nullglob
|
||||
if [[ "$http_code" != "200" ]] || [[ ! -s /tmp/gh_tags.json ]]; then
|
||||
msg_error "Unable to fetch tags for ${repo} (HTTP ${http_code})"
|
||||
rm -f /tmp/gh_tags.json
|
||||
return 1
|
||||
fi
|
||||
|
||||
rm -rf "$tmpdir"
|
||||
echo "$version" >"$version_file"
|
||||
msg_ok "Deployed ${app} ${version} to ${target}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Checks for new GitHub tag (for repos without releases).
|
||||
#
|
||||
# Description:
|
||||
# - Uses get_latest_gh_tag to fetch the latest tag
|
||||
# - Compares it to a local cached version (~/.<app>)
|
||||
# - If newer, sets global CHECK_UPDATE_RELEASE and returns 0
|
||||
#
|
||||
# Usage:
|
||||
# if check_for_gh_tag "guacd" "apache/guacamole-server"; then
|
||||
# fetch_and_deploy_gh_tag "guacd" "apache/guacamole-server" "/opt/guacamole-server"
|
||||
# fi
|
||||
#
|
||||
# Notes:
|
||||
# - For repos that only publish tags, not GitHub Releases
|
||||
# - Same interface as check_for_gh_release
|
||||
# ------------------------------------------------------------------------------
|
||||
check_for_gh_tag() {
|
||||
local app="$1"
|
||||
local repo="$2"
|
||||
local prefix="${3:-}"
|
||||
local app_lc=""
|
||||
app_lc="$(echo "${app,,}" | tr -d ' ')"
|
||||
local current_file="$HOME/.${app_lc}"
|
||||
|
||||
msg_info "Checking for update: ${app}"
|
||||
local tags_json
|
||||
tags_json=$(</tmp/gh_tags.json)
|
||||
rm -f /tmp/gh_tags.json
|
||||
|
||||
# Extract tag names, filter by prefix, exclude pre-release patterns, sort by version
|
||||
local latest=""
|
||||
latest=$(get_latest_gh_tag "$repo" "$prefix") || return 1
|
||||
latest=$(echo "$tags_json" | grep -oP '"name":\s*"\K[^"]+' |
|
||||
{ [[ -n "$prefix" ]] && grep "^${prefix}" || cat; } |
|
||||
grep -viE '(rc|alpha|beta|dev|test|preview|snapshot)' |
|
||||
sort -V | tail -n1)
|
||||
|
||||
local current=""
|
||||
[[ -f "$current_file" ]] && current="$(<"$current_file")"
|
||||
|
||||
if [[ -z "$current" || "$current" != "$latest" ]]; then
|
||||
CHECK_UPDATE_RELEASE="$latest"
|
||||
msg_ok "Update available: ${app} ${current:-not installed} → ${latest}"
|
||||
return 0
|
||||
if [[ -z "$latest" ]]; then
|
||||
msg_warn "No matching tags found for ${repo}${prefix:+ (prefix: $prefix)}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
msg_ok "No update available: ${app} (${latest})"
|
||||
return 1
|
||||
if [[ "$strip_prefix" == "true" && -n "$prefix" ]]; then
|
||||
latest="${latest#"$prefix"}"
|
||||
fi
|
||||
|
||||
echo "$latest"
|
||||
return 0
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
@@ -2292,35 +2219,6 @@ check_for_gh_release() {
|
||||
# Try /latest endpoint for non-pinned versions (most efficient)
|
||||
local releases_json="" http_code=""
|
||||
|
||||
# For pinned versions, query the specific release tag directly
|
||||
if [[ -n "$pinned_version_in" ]]; then
|
||||
http_code=$(curl -sSL --max-time 20 -w "%{http_code}" -o /tmp/gh_check.json \
|
||||
-H 'Accept: application/vnd.github+json' \
|
||||
-H 'X-GitHub-Api-Version: 2022-11-28' \
|
||||
"${header_args[@]}" \
|
||||
"https://api.github.com/repos/${source}/releases/tags/${pinned_version_in}" 2>/dev/null) || true
|
||||
|
||||
if [[ "$http_code" == "200" ]] && [[ -s /tmp/gh_check.json ]]; then
|
||||
releases_json="[$(</tmp/gh_check.json)]"
|
||||
elif [[ "$http_code" == "401" ]]; then
|
||||
msg_error "GitHub API authentication failed (HTTP 401)."
|
||||
if [[ -n "${GITHUB_TOKEN:-}" ]]; then
|
||||
msg_error "Your GITHUB_TOKEN appears to be invalid or expired."
|
||||
else
|
||||
msg_error "The repository may require authentication. Try: export GITHUB_TOKEN=\"ghp_your_token\""
|
||||
fi
|
||||
rm -f /tmp/gh_check.json
|
||||
return 1
|
||||
elif [[ "$http_code" == "403" ]]; then
|
||||
msg_error "GitHub API rate limit exceeded (HTTP 403)."
|
||||
msg_error "To increase the limit, export a GitHub token before running the script:"
|
||||
msg_error " export GITHUB_TOKEN=\"ghp_your_token_here\""
|
||||
rm -f /tmp/gh_check.json
|
||||
return 1
|
||||
fi
|
||||
rm -f /tmp/gh_check.json
|
||||
fi
|
||||
|
||||
if [[ -z "$pinned_version_in" ]]; then
|
||||
http_code=$(curl -sSL --max-time 20 -w "%{http_code}" -o /tmp/gh_check.json \
|
||||
-H 'Accept: application/vnd.github+json' \
|
||||
@@ -2588,8 +2486,6 @@ check_for_codeberg_release() {
|
||||
# ------------------------------------------------------------------------------
|
||||
create_self_signed_cert() {
|
||||
local APP_NAME="${1:-${APPLICATION}}"
|
||||
local HOSTNAME="$(hostname -f)"
|
||||
local IP="$(hostname -I | awk '{print $1}')"
|
||||
local APP_NAME_LC=$(echo "${APP_NAME,,}" | tr -d ' ')
|
||||
local CERT_DIR="/etc/ssl/${APP_NAME_LC}"
|
||||
local CERT_KEY="${CERT_DIR}/${APP_NAME_LC}.key"
|
||||
@@ -2607,8 +2503,8 @@ create_self_signed_cert() {
|
||||
|
||||
mkdir -p "$CERT_DIR"
|
||||
$STD openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 \
|
||||
-subj "/CN=${HOSTNAME}" \
|
||||
-addext "subjectAltName=DNS:${HOSTNAME},DNS:localhost,IP:${IP},IP:127.0.0.1" \
|
||||
-subj "/CN=${APP_NAME}" \
|
||||
-addext "subjectAltName=DNS:${APP_NAME}" \
|
||||
-keyout "$CERT_KEY" \
|
||||
-out "$CERT_CRT" || {
|
||||
msg_error "Failed to create self-signed certificate"
|
||||
@@ -2678,30 +2574,6 @@ function ensure_usr_local_bin_persist() {
|
||||
fi
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# curl_download - Downloads a file with automatic retry and exponential backoff.
|
||||
#
|
||||
# Usage: curl_download <output_file> <url>
|
||||
#
|
||||
# Retries up to 5 times with increasing --max-time (60/120/240/480/960s).
|
||||
# Returns 0 on success, 1 if all attempts fail.
|
||||
# ------------------------------------------------------------------------------
|
||||
function curl_download() {
|
||||
local output="$1"
|
||||
local url="$2"
|
||||
local timeouts=(60 120 240 480 960)
|
||||
|
||||
for i in "${!timeouts[@]}"; do
|
||||
if curl --connect-timeout 15 --max-time "${timeouts[$i]}" -fsSL -o "$output" "$url"; then
|
||||
return 0
|
||||
fi
|
||||
if ((i < ${#timeouts[@]} - 1)); then
|
||||
msg_warn "Download timed out after ${timeouts[$i]}s, retrying... (attempt $((i + 2))/${#timeouts[@]})"
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Downloads and deploys latest Codeberg release (source, binary, tarball, asset).
|
||||
#
|
||||
@@ -2759,7 +2631,8 @@ function fetch_and_deploy_codeberg_release() {
|
||||
local app_lc=$(echo "${app,,}" | tr -d ' ')
|
||||
local version_file="$HOME/.${app_lc}"
|
||||
|
||||
local api_timeouts=(60 120 240)
|
||||
local api_timeout="--connect-timeout 10 --max-time 60"
|
||||
local download_timeout="--connect-timeout 15 --max-time 900"
|
||||
|
||||
local current_version=""
|
||||
[[ -f "$version_file" ]] && current_version=$(<"$version_file")
|
||||
@@ -2799,7 +2672,7 @@ function fetch_and_deploy_codeberg_release() {
|
||||
|
||||
# Codeberg archive URL format: https://codeberg.org/{owner}/{repo}/archive/{tag}.tar.gz
|
||||
local archive_url="https://codeberg.org/$repo/archive/${tag_name}.tar.gz"
|
||||
if curl_download "$tmpdir/$filename" "$archive_url"; then
|
||||
if curl $download_timeout -fsSL -o "$tmpdir/$filename" "$archive_url"; then
|
||||
download_success=true
|
||||
fi
|
||||
|
||||
@@ -2846,18 +2719,16 @@ function fetch_and_deploy_codeberg_release() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
local attempt=0 success=false resp http_code
|
||||
local max_retries=3 retry_delay=2 attempt=1 success=false resp http_code
|
||||
|
||||
while ((attempt < ${#api_timeouts[@]})); do
|
||||
resp=$(curl --connect-timeout 10 --max-time "${api_timeouts[$attempt]}" -fsSL -w "%{http_code}" -o /tmp/codeberg_rel.json "$api_url") && success=true && break
|
||||
while ((attempt <= max_retries)); do
|
||||
resp=$(curl $api_timeout -fsSL -w "%{http_code}" -o /tmp/codeberg_rel.json "$api_url") && success=true && break
|
||||
sleep "$retry_delay"
|
||||
((attempt++))
|
||||
if ((attempt < ${#api_timeouts[@]})); then
|
||||
msg_warn "API request timed out after ${api_timeouts[$((attempt - 1))]}s, retrying... (attempt $((attempt + 1))/${#api_timeouts[@]})"
|
||||
fi
|
||||
done
|
||||
|
||||
if ! $success; then
|
||||
msg_error "Failed to fetch release metadata from $api_url after ${#api_timeouts[@]} attempts"
|
||||
msg_error "Failed to fetch release metadata from $api_url after $max_retries attempts"
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -2898,7 +2769,7 @@ function fetch_and_deploy_codeberg_release() {
|
||||
|
||||
# Codeberg archive URL format
|
||||
local archive_url="https://codeberg.org/$repo/archive/${tag_name}.tar.gz"
|
||||
if curl_download "$tmpdir/$filename" "$archive_url"; then
|
||||
if curl $download_timeout -fsSL -o "$tmpdir/$filename" "$archive_url"; then
|
||||
download_success=true
|
||||
fi
|
||||
|
||||
@@ -2972,7 +2843,7 @@ function fetch_and_deploy_codeberg_release() {
|
||||
fi
|
||||
|
||||
filename="${url_match##*/}"
|
||||
curl_download "$tmpdir/$filename" "$url_match" || {
|
||||
curl $download_timeout -fsSL -o "$tmpdir/$filename" "$url_match" || {
|
||||
msg_error "Download failed: $url_match"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
@@ -3015,7 +2886,7 @@ function fetch_and_deploy_codeberg_release() {
|
||||
}
|
||||
|
||||
filename="${asset_url##*/}"
|
||||
curl_download "$tmpdir/$filename" "$asset_url" || {
|
||||
curl $download_timeout -fsSL -o "$tmpdir/$filename" "$asset_url" || {
|
||||
msg_error "Download failed: $asset_url"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
@@ -3116,7 +2987,7 @@ function fetch_and_deploy_codeberg_release() {
|
||||
local target_file="$app"
|
||||
[[ "$use_filename" == "true" ]] && target_file="$filename"
|
||||
|
||||
curl_download "$target/$target_file" "$asset_url" || {
|
||||
curl $download_timeout -fsSL -o "$target/$target_file" "$asset_url" || {
|
||||
msg_error "Download failed: $asset_url"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
@@ -3311,7 +3182,8 @@ function fetch_and_deploy_gh_release() {
|
||||
local app_lc=$(echo "${app,,}" | tr -d ' ')
|
||||
local version_file="$HOME/.${app_lc}"
|
||||
|
||||
local api_timeouts=(60 120 240)
|
||||
local api_timeout="--connect-timeout 10 --max-time 60"
|
||||
local download_timeout="--connect-timeout 15 --max-time 900"
|
||||
|
||||
local current_version=""
|
||||
[[ -f "$version_file" ]] && current_version=$(<"$version_file")
|
||||
@@ -3331,10 +3203,10 @@ function fetch_and_deploy_gh_release() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
local max_retries=${#api_timeouts[@]} retry_delay=2 attempt=1 success=false http_code
|
||||
local max_retries=3 retry_delay=2 attempt=1 success=false http_code
|
||||
|
||||
while ((attempt <= max_retries)); do
|
||||
http_code=$(curl --connect-timeout 10 --max-time "${api_timeouts[$((attempt - 1))]:-240}" -sSL -w "%{http_code}" -o /tmp/gh_rel.json "${header[@]}" "$api_url" 2>/dev/null) || true
|
||||
http_code=$(curl $api_timeout -sSL -w "%{http_code}" -o /tmp/gh_rel.json "${header[@]}" "$api_url" 2>/dev/null) || true
|
||||
if [[ "$http_code" == "200" ]]; then
|
||||
success=true
|
||||
break
|
||||
@@ -3408,7 +3280,7 @@ function fetch_and_deploy_gh_release() {
|
||||
local direct_tarball_url="https://github.com/$repo/archive/refs/tags/$tag_name.tar.gz"
|
||||
filename="${app_lc}-${version_safe}.tar.gz"
|
||||
|
||||
curl_download "$tmpdir/$filename" "$direct_tarball_url" || {
|
||||
curl $download_timeout -fsSL -o "$tmpdir/$filename" "$direct_tarball_url" || {
|
||||
msg_error "Download failed: $direct_tarball_url"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
@@ -3511,7 +3383,7 @@ function fetch_and_deploy_gh_release() {
|
||||
fi
|
||||
|
||||
filename="${url_match##*/}"
|
||||
curl_download "$tmpdir/$filename" "$url_match" || {
|
||||
curl $download_timeout -fsSL -o "$tmpdir/$filename" "$url_match" || {
|
||||
msg_error "Download failed: $url_match"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
@@ -3578,7 +3450,7 @@ function fetch_and_deploy_gh_release() {
|
||||
}
|
||||
|
||||
filename="${asset_url##*/}"
|
||||
curl_download "$tmpdir/$filename" "$asset_url" || {
|
||||
curl $download_timeout -fsSL -o "$tmpdir/$filename" "$asset_url" || {
|
||||
msg_error "Download failed: $asset_url"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
@@ -3699,7 +3571,7 @@ function fetch_and_deploy_gh_release() {
|
||||
local target_file="$app"
|
||||
[[ "$use_filename" == "true" ]] && target_file="$filename"
|
||||
|
||||
curl_download "$target/$target_file" "$asset_url" || {
|
||||
curl $download_timeout -fsSL -o "$target/$target_file" "$asset_url" || {
|
||||
msg_error "Download failed: $asset_url"
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
@@ -4256,8 +4128,6 @@ function setup_gs() {
|
||||
# - NVIDIA requires matching host driver version
|
||||
# ------------------------------------------------------------------------------
|
||||
function setup_hwaccel() {
|
||||
local service_user="${1:-}"
|
||||
|
||||
# Check if user explicitly disabled GPU in advanced settings
|
||||
# ENABLE_GPU is exported from build.func
|
||||
if [[ "${ENABLE_GPU:-no}" == "no" ]]; then
|
||||
@@ -4509,7 +4379,7 @@ function setup_hwaccel() {
|
||||
# ═══════════════════════════════════════════════════════════════════════════
|
||||
# Device Permissions
|
||||
# ═══════════════════════════════════════════════════════════════════════════
|
||||
_setup_gpu_permissions "$in_ct" "$service_user"
|
||||
_setup_gpu_permissions "$in_ct"
|
||||
|
||||
cache_installed_version "hwaccel" "1.0"
|
||||
msg_ok "Setup Hardware Acceleration"
|
||||
@@ -4702,6 +4572,9 @@ _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"
|
||||
}
|
||||
|
||||
@@ -4749,9 +4622,16 @@ _setup_rocm() {
|
||||
return 0
|
||||
}
|
||||
|
||||
# Note: The amdgpu/latest/ubuntu repo (kernel driver packages) is intentionally
|
||||
# omitted — kernel drivers are managed by the Proxmox host, not the LXC container.
|
||||
# Only the ROCm userspace compute stack is needed inside the container.
|
||||
# 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
|
||||
@@ -4760,26 +4640,7 @@ Pin: release o=repo.radeon.com
|
||||
Pin-Priority: 600
|
||||
EOF
|
||||
|
||||
# apt update with retry — repo.radeon.com CDN can be mid-sync (transient size mismatches).
|
||||
# Run with ERR trap disabled so a transient failure does not abort the entire install.
|
||||
local _apt_ok=0
|
||||
for _attempt in 1 2 3; do
|
||||
if (
|
||||
set +e
|
||||
apt-get update -qq 2>&1
|
||||
exit $?
|
||||
) 2>/dev/null; then
|
||||
_apt_ok=1
|
||||
break
|
||||
fi
|
||||
msg_warn "apt update failed (attempt ${_attempt}/3) — AMD repo may be temporarily unavailable, retrying in 30s…"
|
||||
sleep 30
|
||||
done
|
||||
if [[ $_apt_ok -eq 0 ]]; then
|
||||
msg_warn "apt update still failing after 3 attempts — skipping ROCm install"
|
||||
return 0
|
||||
fi
|
||||
|
||||
$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"
|
||||
@@ -5143,7 +5004,6 @@ EOF
|
||||
# ══════════════════════════════════════════════════════════════════════════════
|
||||
_setup_gpu_permissions() {
|
||||
local in_ct="$1"
|
||||
local service_user="${2:-}"
|
||||
|
||||
# /dev/dri permissions (Intel/AMD)
|
||||
if [[ "$in_ct" == "0" && -d /dev/dri ]]; then
|
||||
@@ -5210,12 +5070,6 @@ _setup_gpu_permissions() {
|
||||
chmod 666 /dev/kfd 2>/dev/null || true
|
||||
msg_info "AMD ROCm compute device configured"
|
||||
fi
|
||||
|
||||
# Add service user to render and video groups for GPU hardware acceleration
|
||||
if [[ -n "$service_user" ]]; then
|
||||
usermod -aG render "$service_user" 2>/dev/null || true
|
||||
usermod -aG video "$service_user" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -6698,38 +6552,22 @@ EOF
|
||||
# - Optionally uses official PGDG repository for specific versions
|
||||
# - Detects existing PostgreSQL version
|
||||
# - Dumps all databases before upgrade
|
||||
# - Installs optional PG_MODULES (e.g. postgis, contrib, cron)
|
||||
# - Installs optional PG_MODULES (e.g. postgis, contrib)
|
||||
# - Restores dumped data post-upgrade
|
||||
#
|
||||
# Variables:
|
||||
# USE_PGDG_REPO - Use official PGDG repository (default: true)
|
||||
# Set to "false" to use distro packages instead
|
||||
# PG_VERSION - Major PostgreSQL version (e.g. 15, 16) (default: 16)
|
||||
# PG_MODULES - Comma-separated list of modules (e.g. "postgis,contrib,cron")
|
||||
# PG_MODULES - Comma-separated list of modules (e.g. "postgis,contrib")
|
||||
#
|
||||
# Examples:
|
||||
# setup_postgresql # Uses PGDG repo, PG 16
|
||||
# PG_VERSION="17" setup_postgresql # Specific version from PGDG
|
||||
# USE_PGDG_REPO=false setup_postgresql # Uses distro package instead
|
||||
# PG_VERSION="17" PG_MODULES="cron" setup_postgresql # With pg_cron module
|
||||
# setup_postgresql # Uses PGDG repo, PG 16
|
||||
# PG_VERSION="17" setup_postgresql # Specific version from PGDG
|
||||
# USE_PGDG_REPO=false setup_postgresql # Uses distro package instead
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# Internal helper: Configure shared_preload_libraries for pg_cron
|
||||
_configure_pg_cron_preload() {
|
||||
local modules="${1:-}"
|
||||
[[ -z "$modules" ]] && return 0
|
||||
if [[ ",$modules," == *",cron,"* ]]; then
|
||||
local current_libs
|
||||
current_libs=$(sudo -u postgres psql -tAc "SHOW shared_preload_libraries;" 2>/dev/null || echo "")
|
||||
if [[ "$current_libs" != *"pg_cron"* ]]; then
|
||||
local new_libs="${current_libs:+${current_libs},}pg_cron"
|
||||
$STD sudo -u postgres psql -c "ALTER SYSTEM SET shared_preload_libraries = '${new_libs}';"
|
||||
$STD systemctl restart postgresql
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
setup_postgresql() {
|
||||
function setup_postgresql() {
|
||||
local PG_VERSION="${PG_VERSION:-16}"
|
||||
local PG_MODULES="${PG_MODULES:-}"
|
||||
local USE_PGDG_REPO="${USE_PGDG_REPO:-true}"
|
||||
@@ -6767,7 +6605,6 @@ setup_postgresql() {
|
||||
$STD apt install -y "postgresql-${CURRENT_PG_VERSION}-${module}" 2>/dev/null || true
|
||||
done
|
||||
fi
|
||||
_configure_pg_cron_preload "$PG_MODULES"
|
||||
return 0
|
||||
fi
|
||||
|
||||
@@ -6803,7 +6640,6 @@ setup_postgresql() {
|
||||
$STD apt install -y "postgresql-${INSTALLED_VERSION}-${module}" 2>/dev/null || true
|
||||
done
|
||||
fi
|
||||
_configure_pg_cron_preload "$PG_MODULES"
|
||||
return 0
|
||||
fi
|
||||
|
||||
@@ -6825,7 +6661,6 @@ setup_postgresql() {
|
||||
$STD apt install -y "postgresql-${PG_VERSION}-${module}" 2>/dev/null || true
|
||||
done
|
||||
fi
|
||||
_configure_pg_cron_preload "$PG_MODULES"
|
||||
return 0
|
||||
fi
|
||||
|
||||
@@ -6853,16 +6688,13 @@ setup_postgresql() {
|
||||
local SUITE
|
||||
case "$DISTRO_CODENAME" in
|
||||
trixie | forky | sid)
|
||||
|
||||
if verify_repo_available "https://apt.postgresql.org/pub/repos/apt" "trixie-pgdg"; then
|
||||
SUITE="trixie-pgdg"
|
||||
|
||||
else
|
||||
msg_warn "PGDG repo not available for ${DISTRO_CODENAME}, falling back to distro packages"
|
||||
USE_PGDG_REPO=false setup_postgresql
|
||||
return $?
|
||||
fi
|
||||
|
||||
;;
|
||||
*)
|
||||
SUITE=$(get_fallback_suite "$DISTRO_ID" "$DISTRO_CODENAME" "https://apt.postgresql.org/pub/repos/apt")
|
||||
@@ -6946,7 +6778,6 @@ setup_postgresql() {
|
||||
}
|
||||
done
|
||||
fi
|
||||
_configure_pg_cron_preload "$PG_MODULES"
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -6965,7 +6796,6 @@ setup_postgresql() {
|
||||
# PG_DB_NAME="immich" PG_DB_USER="immich" PG_DB_EXTENSIONS="pgvector" setup_postgresql_db
|
||||
# PG_DB_NAME="ghostfolio" PG_DB_USER="ghostfolio" PG_DB_GRANT_SUPERUSER="true" setup_postgresql_db
|
||||
# PG_DB_NAME="adventurelog" PG_DB_USER="adventurelog" PG_DB_EXTENSIONS="postgis" setup_postgresql_db
|
||||
# PG_DB_NAME="splitpro" PG_DB_USER="splitpro" PG_DB_EXTENSIONS="pg_cron" setup_postgresql_db
|
||||
#
|
||||
# Variables:
|
||||
# PG_DB_NAME - Database name (required)
|
||||
@@ -6997,13 +6827,6 @@ function setup_postgresql_db() {
|
||||
$STD sudo -u postgres psql -c "CREATE ROLE $PG_DB_USER WITH LOGIN PASSWORD '$PG_DB_PASS';"
|
||||
$STD sudo -u postgres psql -c "CREATE DATABASE $PG_DB_NAME WITH OWNER $PG_DB_USER ENCODING 'UTF8' TEMPLATE template0;"
|
||||
|
||||
# Configure pg_cron database BEFORE creating the extension (must be set before pg_cron loads)
|
||||
if [[ -n "${PG_DB_EXTENSIONS:-}" ]] && [[ ",${PG_DB_EXTENSIONS//[[:space:]]/}," == *",pg_cron,"* ]]; then
|
||||
$STD sudo -u postgres psql -c "ALTER SYSTEM SET cron.database_name = '${PG_DB_NAME}';"
|
||||
$STD sudo -u postgres psql -c "ALTER SYSTEM SET cron.timezone = 'UTC';"
|
||||
$STD systemctl restart postgresql
|
||||
fi
|
||||
|
||||
# Install extensions (comma-separated)
|
||||
if [[ -n "${PG_DB_EXTENSIONS:-}" ]]; then
|
||||
IFS=',' read -ra EXT_LIST <<<"${PG_DB_EXTENSIONS:-}"
|
||||
@@ -7013,12 +6836,6 @@ function setup_postgresql_db() {
|
||||
done
|
||||
fi
|
||||
|
||||
# Grant pg_cron schema permissions to DB user
|
||||
if [[ -n "${PG_DB_EXTENSIONS:-}" ]] && [[ ",${PG_DB_EXTENSIONS//[[:space:]]/}," == *",pg_cron,"* ]]; then
|
||||
$STD sudo -u postgres psql -d "$PG_DB_NAME" -c "GRANT USAGE ON SCHEMA cron TO ${PG_DB_USER};"
|
||||
$STD sudo -u postgres psql -d "$PG_DB_NAME" -c "GRANT ALL ON ALL TABLES IN SCHEMA cron TO ${PG_DB_USER};"
|
||||
fi
|
||||
|
||||
# ALTER ROLE settings for Django/Rails compatibility (unless skipped)
|
||||
if [[ "${PG_DB_SKIP_ALTER_ROLE:-}" != "true" ]]; then
|
||||
$STD sudo -u postgres psql -c "ALTER ROLE $PG_DB_USER SET client_encoding TO 'utf8';"
|
||||
@@ -7060,6 +6877,7 @@ function setup_postgresql_db() {
|
||||
export PG_DB_USER
|
||||
export PG_DB_PASS
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Installs rbenv and ruby-build, installs Ruby and optionally Rails.
|
||||
#
|
||||
|
||||
@@ -134,20 +134,16 @@ manage_states() {
|
||||
read -rp "Shutdown source and start new container? [Y/n]: " answer
|
||||
answer=${answer:-Y}
|
||||
if [[ $answer =~ ^[Yy] ]]; then
|
||||
pct shutdown "$CONTAINER_ID"
|
||||
for i in {1..36}; do
|
||||
sleep 5
|
||||
! pct status "$CONTAINER_ID" | grep -q running && break
|
||||
done
|
||||
if pct status "$CONTAINER_ID" | grep -q running; then
|
||||
pct shutdown "$CONTAINER_ID"
|
||||
for i in {1..36}; do
|
||||
sleep 5
|
||||
! pct status "$CONTAINER_ID" | grep -q running && break
|
||||
done
|
||||
if pct status "$CONTAINER_ID" | grep -q running; then
|
||||
read -rp "Timeout reached. Force shutdown? [Y/n]: " force
|
||||
if [[ ${force:-Y} =~ ^[Yy] ]]; then
|
||||
pkill -9 -f "lxc-start -F -n $CONTAINER_ID"
|
||||
fi
|
||||
read -rp "Timeout reached. Force shutdown? [Y/n]: " force
|
||||
if [[ ${force:-Y} =~ ^[Yy] ]]; then
|
||||
pkill -9 -f "lxc-start -F -n $CONTAINER_ID"
|
||||
fi
|
||||
else
|
||||
msg_custom "ℹ️" "\e[36m" "Source container $CONTAINER_ID is already stopped"
|
||||
fi
|
||||
pct start "$NEW_CONTAINER_ID"
|
||||
msg_ok "New container started"
|
||||
|
||||
@@ -426,23 +426,16 @@ for container in $CHOICE; do
|
||||
elif [ $exit_code -eq 75 ]; then
|
||||
echo -e "${YW}[WARN]${CL} Container $container skipped (requires interactive mode)"
|
||||
elif [ "$BACKUP_CHOICE" == "yes" ]; then
|
||||
msg_error "Update failed for container $container (exit code: $exit_code) — attempting restore"
|
||||
msg_info "Restoring LXC $container from backup ($STORAGE_CHOICE)"
|
||||
msg_info "Restoring LXC from backup"
|
||||
pct stop $container
|
||||
LXC_STORAGE=$(pct config $container | awk -F '[:,]' '/rootfs/ {print $2}')
|
||||
BACKUP_ENTRY=$(pvesm list "$STORAGE_CHOICE" 2>/dev/null | awk -v ctid="$container" '$1 ~ "vzdump-lxc-"ctid"-" || $1 ~ "/ct/"ctid"/" {print $1}' | sort -r | head -n1)
|
||||
if [ -z "$BACKUP_ENTRY" ]; then
|
||||
msg_error "No backup found in storage $STORAGE_CHOICE for container $container"
|
||||
exit 235
|
||||
fi
|
||||
msg_info "Restoring from: $BACKUP_ENTRY"
|
||||
pct restore $container "$BACKUP_ENTRY" --storage $LXC_STORAGE --force >/dev/null 2>&1
|
||||
pct restore $container /var/lib/vz/dump/vzdump-lxc-${container}-*.tar.zst --storage $LXC_STORAGE --force >/dev/null 2>&1
|
||||
pct start $container
|
||||
restorestatus=$?
|
||||
if [ $restorestatus -eq 0 ]; then
|
||||
pct start $container
|
||||
msg_ok "Container $container successfully restored from backup"
|
||||
msg_ok "Restored LXC from backup"
|
||||
else
|
||||
msg_error "Restore failed for container $container"
|
||||
msg_error "Restored LXC from backup failed"
|
||||
exit 235
|
||||
fi
|
||||
else
|
||||
|
||||
@@ -22,7 +22,7 @@ echo -e "\n Loading..."
|
||||
GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//')
|
||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
METHOD=""
|
||||
NSAPP="archlinux-vm"
|
||||
NSAPP="arch-linux-vm"
|
||||
var_os="arch-linux"
|
||||
var_version="n.d."
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ echo -e "\n Loading..."
|
||||
GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//')
|
||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
METHOD=""
|
||||
NSAPP="debian-13-vm"
|
||||
NSAPP="debian13vm"
|
||||
var_os="debian"
|
||||
var_version="13"
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ echo -e "\n Loading..."
|
||||
GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//')
|
||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
METHOD=""
|
||||
NSAPP="debian-vm"
|
||||
NSAPP="debian12vm"
|
||||
var_os="debian"
|
||||
var_version="12"
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:
|
||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
VERSIONS=(stable beta dev)
|
||||
METHOD=""
|
||||
NSAPP="haos-vm"
|
||||
NSAPP="homeassistant-os"
|
||||
var_os="homeassistant"
|
||||
DISK_SIZE="32G"
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ echo -e "Loading..."
|
||||
GEN_MAC=$(echo '00 60 2f'$(od -An -N3 -t xC /dev/urandom) | sed -e 's/ /:/g' | tr '[:lower:]' '[:upper:]')
|
||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
METHOD=""
|
||||
NSAPP="mikrotik-routeros"
|
||||
NSAPP="mikrotik-router-os"
|
||||
var_os="mikrotik"
|
||||
var_version=" "
|
||||
DISK_SIZE="1G"
|
||||
|
||||
@@ -22,7 +22,7 @@ echo -e "\n Loading..."
|
||||
GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//')
|
||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
METHOD=""
|
||||
NSAPP="nextcloud-vm"
|
||||
NSAPP="turnkey-nextcloud"
|
||||
var_os="turnkey-nextcloud"
|
||||
var_version="n.d."
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ echo -e "\n Loading..."
|
||||
GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//')
|
||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
METHOD=""
|
||||
NSAPP="owncloud-vm"
|
||||
NSAPP="turnkey-owncloud-vm"
|
||||
var_os="owncloud"
|
||||
var_version="18.0"
|
||||
APP="TurnKey ownCloud VM"
|
||||
|
||||
@@ -23,7 +23,6 @@ echo -e "\n Loading..."
|
||||
GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//')
|
||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
METHOD=""
|
||||
NSAPP="truenas-vm"
|
||||
|
||||
YW=$(echo "\033[33m")
|
||||
BL=$(echo "\033[36m")
|
||||
|
||||
@@ -22,7 +22,7 @@ echo -e "\n Loading..."
|
||||
GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//')
|
||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
METHOD=""
|
||||
NSAPP="ubuntu2204-vm"
|
||||
NSAPP="ubuntu-2204-vm"
|
||||
var_os="ubuntu"
|
||||
var_version="2204"
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ echo -e "\n Loading..."
|
||||
GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//')
|
||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
METHOD=""
|
||||
NSAPP="ubuntu2404-vm"
|
||||
NSAPP="ubuntu-2404-vm"
|
||||
var_os="ubuntu"
|
||||
var_version="2404"
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ echo -e "\n Loading..."
|
||||
GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//')
|
||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
METHOD=""
|
||||
NSAPP="ubuntu2504-vm"
|
||||
NSAPP="ubuntu-2504-vm"
|
||||
var_os="ubuntu"
|
||||
var_version="2504"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user