Compare commits
1 Commits
delete_fil
...
michelroeg
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b9e55984b |
7
.gitattributes
vendored
7
.gitattributes
vendored
@@ -10,6 +10,11 @@
|
||||
# Treat Golang files as Go (for /api/)
|
||||
api/**/*.go linguist-language=Go
|
||||
|
||||
# ---------------------------------------
|
||||
# Treat frontend as JavaScript/TypeScript (optional)
|
||||
frontend/**/*.ts linguist-language=TypeScript
|
||||
frontend/**/*.js linguist-language=JavaScript
|
||||
|
||||
# ---------------------------------------
|
||||
# Exclude documentation from stats
|
||||
*.md linguist-documentation
|
||||
@@ -21,7 +26,7 @@ SECURITY.md linguist-documentation
|
||||
# ---------------------------------------
|
||||
# Exclude generated/config files
|
||||
*.json linguist-generated
|
||||
json/*.json linguist-generated=false
|
||||
frontend/public/json/*.json linguist-generated=false
|
||||
*.lock linguist-generated
|
||||
*.yml linguist-generated
|
||||
*.yaml linguist-generated
|
||||
|
||||
2
.github/autolabeler-config.json
generated
vendored
2
.github/autolabeler-config.json
generated
vendored
@@ -97,7 +97,7 @@
|
||||
{
|
||||
"fileStatus": "modified",
|
||||
"includeGlobs": [
|
||||
"json/**"
|
||||
"frontend/public/json/**"
|
||||
],
|
||||
"excludeGlobs": []
|
||||
}
|
||||
|
||||
3
.github/pull_request_template.md
generated
vendored
3
.github/pull_request_template.md
generated
vendored
@@ -49,6 +49,3 @@ Link: #
|
||||
- [ ] The application has **600+ GitHub stars**
|
||||
- [ ] Official **release tarballs** are published
|
||||
- [ ] I understand that not all scripts will be accepted due to various reasons and criteria by the community-scripts ORG
|
||||
|
||||
## 🌐 Source
|
||||
<!-- Add any sources and github links. -->
|
||||
|
||||
2
.github/workflows/bak/get-versions-from-gh.yaml
generated
vendored
2
.github/workflows/bak/get-versions-from-gh.yaml
generated
vendored
@@ -47,7 +47,7 @@ jobs:
|
||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --global user.name "GitHub Actions[bot]"
|
||||
git checkout -b update_versions || git checkout update_versions
|
||||
git add json/versions.json
|
||||
git add frontend/public/json/versions.json
|
||||
if git diff --cached --quiet; then
|
||||
echo "No changes detected."
|
||||
echo "changed=false" >> "$GITHUB_ENV"
|
||||
|
||||
4
.github/workflows/bak/get-versions-from-newreleases.yaml
generated
vendored
4
.github/workflows/bak/get-versions-from-newreleases.yaml
generated
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
run: |
|
||||
page=1
|
||||
projects_file="project_json"
|
||||
output_file="json/versions.json"
|
||||
output_file="frontend/public/json/versions.json"
|
||||
|
||||
echo "[]" > $output_file
|
||||
|
||||
@@ -95,7 +95,7 @@ jobs:
|
||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --global user.name "GitHub Actions[bot]"
|
||||
git checkout -b update_versions || git checkout update_versions
|
||||
git add json/versions.json
|
||||
git add frontend/public/json/versions.json
|
||||
if git diff --cached --quiet; then
|
||||
echo "No changes detected."
|
||||
echo "changed=false" >> "$GITHUB_ENV"
|
||||
|
||||
4
.github/workflows/bak/update-versions-github.yml
generated
vendored
4
.github/workflows/bak/update-versions-github.yml
generated
vendored
@@ -11,8 +11,8 @@ permissions:
|
||||
pull-requests: write
|
||||
|
||||
env:
|
||||
SOURCES_FILE: json/version-sources.json
|
||||
VERSIONS_FILE: json/versions.json
|
||||
SOURCES_FILE: frontend/public/json/version-sources.json
|
||||
VERSIONS_FILE: frontend/public/json/versions.json
|
||||
|
||||
jobs:
|
||||
update-versions:
|
||||
|
||||
16
.github/workflows/create-ready-for-testing-message.yml
generated
vendored
16
.github/workflows/create-ready-for-testing-message.yml
generated
vendored
@@ -7,7 +7,6 @@ on:
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
actions: write
|
||||
|
||||
jobs:
|
||||
post_to_discord:
|
||||
@@ -60,19 +59,19 @@ jobs:
|
||||
FILES=(
|
||||
"ct/${TITLE}.sh"
|
||||
"install/${TITLE}-install.sh"
|
||||
"json/${TITLE}.json"
|
||||
"frontend/public/json/${TITLE}.json"
|
||||
)
|
||||
;;
|
||||
vm)
|
||||
FILES=(
|
||||
"vm/${TITLE}.sh"
|
||||
"json/${TITLE}.json"
|
||||
"frontend/public/json/${TITLE}.json"
|
||||
)
|
||||
;;
|
||||
addon)
|
||||
FILES=(
|
||||
"tools/addon/${TITLE}.sh"
|
||||
"json/${TITLE}.json"
|
||||
"frontend/public/json/${TITLE}.json"
|
||||
)
|
||||
;;
|
||||
pve)
|
||||
@@ -123,7 +122,7 @@ jobs:
|
||||
JSON_FILE=""
|
||||
case "$SCRIPT_TYPE" in
|
||||
ct|vm|addon)
|
||||
JSON_FILE="json/${TITLE}.json"
|
||||
JSON_FILE="frontend/public/json/${TITLE}.json"
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -218,10 +217,3 @@ jobs:
|
||||
echo -e "$MESSAGE" > comment.txt
|
||||
sed -i '/Discussion & issue tracking:/,$d' comment.txt
|
||||
gh issue comment ${{ github.event.issue.number }} --repo ${{ github.repository }} --body-file comment.txt
|
||||
|
||||
- name: Push script JSON to PocketBase
|
||||
if: env.SCRIPT_TYPE == 'ct' || env.SCRIPT_TYPE == 'vm' || env.SCRIPT_TYPE == 'addon'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh workflow run push_json_to_pocketbase.yml --repo ${{ github.repository }} -f script_slug=${{ env.TITLE }}
|
||||
|
||||
8
.github/workflows/delete_new_script.yaml
generated
vendored
8
.github/workflows/delete_new_script.yaml
generated
vendored
@@ -124,20 +124,20 @@ jobs:
|
||||
rm -f "ct/${TITLE}.sh"
|
||||
rm -f "ct/headers/${TITLE}"
|
||||
rm -f "install/${TITLE}-install.sh"
|
||||
rm -f "json/${TITLE}.json"
|
||||
rm -f "frontend/public/json/${TITLE}.json"
|
||||
# Also try alpine variant
|
||||
if [[ "$TITLE" == alpine-* ]]; then
|
||||
stripped="${TITLE#alpine-}"
|
||||
rm -f "json/${stripped}.json"
|
||||
rm -f "frontend/public/json/${stripped}.json"
|
||||
fi
|
||||
;;
|
||||
vm)
|
||||
rm -f "vm/${TITLE}.sh"
|
||||
rm -f "json/${TITLE}.json"
|
||||
rm -f "frontend/public/json/${TITLE}.json"
|
||||
;;
|
||||
addon)
|
||||
rm -f "tools/addon/${TITLE}.sh"
|
||||
rm -f "json/${TITLE}.json"
|
||||
rm -f "frontend/public/json/${TITLE}.json"
|
||||
;;
|
||||
pve)
|
||||
rm -f "tools/pve/${TITLE}.sh"
|
||||
|
||||
77
.github/workflows/frontend-cicd.yml
generated
vendored
Normal file
77
.github/workflows/frontend-cicd.yml
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
# Based on https://github.com/actions/starter-workflows/blob/main/pages/nextjs.yml
|
||||
|
||||
name: Frontend CI/CD
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
paths:
|
||||
- frontend/**
|
||||
|
||||
pull_request:
|
||||
branches: ["main"]
|
||||
types: [opened, synchronize, reopened, edited]
|
||||
paths:
|
||||
- frontend/**
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: pages-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: github.repository == 'community-scripts/ProxmoxVED'
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: frontend # Set default working directory for all run steps
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
cache: npm
|
||||
cache-dependency-path: frontend/package-lock.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci --prefer-offline --legacy-peer-deps
|
||||
|
||||
- name: Run tests
|
||||
run: npm run test
|
||||
|
||||
- name: Configure Next.js for pages
|
||||
uses: actions/configure-pages@v5
|
||||
with:
|
||||
static_site_generator: next
|
||||
|
||||
- name: Build with Next.js
|
||||
run: npm run build
|
||||
|
||||
- name: Upload artifact
|
||||
if: github.ref == 'refs/heads/main'
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: frontend/out
|
||||
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: github.ref == 'refs/heads/main' && github.repository == 'community-scripts/ProxmoxVED'
|
||||
permissions:
|
||||
pages: write
|
||||
id-token: write
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
40
.github/workflows/move-to-main-repo.yaml
generated
vendored
40
.github/workflows/move-to-main-repo.yaml
generated
vendored
@@ -100,6 +100,26 @@ jobs:
|
||||
files_found="false"
|
||||
missing_files+="install/${script_name}-install.sh "
|
||||
fi
|
||||
# JSON check with alpine fallback
|
||||
json_file="frontend/public/json/${script_name}.json"
|
||||
if [[ ! -f "$json_file" ]]; then
|
||||
if [[ "$script_name" == alpine-* ]]; then
|
||||
stripped_name="${script_name#alpine-}"
|
||||
alt_json="frontend/public/json/${stripped_name}.json"
|
||||
if [[ -f "$alt_json" ]]; then
|
||||
echo "Using alpine fallback JSON: $alt_json"
|
||||
echo "json_fallback=$alt_json" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "json file not found: $json_file"
|
||||
files_found="false"
|
||||
missing_files+="$json_file "
|
||||
fi
|
||||
else
|
||||
echo "json file not found: $json_file"
|
||||
files_found="false"
|
||||
missing_files+="$json_file "
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
vm)
|
||||
if [[ ! -f "vm/${script_name}.sh" ]]; then
|
||||
@@ -107,6 +127,11 @@ jobs:
|
||||
files_found="false"
|
||||
missing_files+="vm/${script_name}.sh "
|
||||
fi
|
||||
# JSON is optional for VMs but check anyway
|
||||
json_file="frontend/public/json/${script_name}.json"
|
||||
if [[ ! -f "$json_file" ]]; then
|
||||
echo "json file not found (optional): $json_file"
|
||||
fi
|
||||
;;
|
||||
addon)
|
||||
if [[ ! -f "tools/addon/${script_name}.sh" ]]; then
|
||||
@@ -114,6 +139,11 @@ jobs:
|
||||
files_found="false"
|
||||
missing_files+="tools/addon/${script_name}.sh "
|
||||
fi
|
||||
# JSON is optional for addons
|
||||
json_file="frontend/public/json/${script_name}.json"
|
||||
if [[ ! -f "$json_file" ]]; then
|
||||
echo "json file not found (optional): $json_file"
|
||||
fi
|
||||
;;
|
||||
pve)
|
||||
if [[ ! -f "tools/pve/${script_name}.sh" ]]; then
|
||||
@@ -160,6 +190,7 @@ jobs:
|
||||
run: |
|
||||
script_name="${{ steps.list_issues.outputs.script_name }}"
|
||||
script_type="${{ steps.list_issues.outputs.script_type }}"
|
||||
json_fallback="${{ steps.check_files.outputs.json_fallback }}"
|
||||
|
||||
git clone https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/community-scripts/ProxmoxVE.git ProxmoxVE
|
||||
cd ProxmoxVE
|
||||
@@ -196,6 +227,13 @@ jobs:
|
||||
cp ../ct/headers/${script_name} ct/headers/ 2>/dev/null || true
|
||||
cp ../install/${script_name}-install.sh install/
|
||||
|
||||
# Handle JSON with alpine fallback
|
||||
if [[ -n "$json_fallback" ]]; then
|
||||
cp ../${json_fallback} frontend/public/json/ || true
|
||||
else
|
||||
cp ../frontend/public/json/${script_name}.json frontend/public/json/ 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Update URLs in ct script
|
||||
sed -i "s|https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func|https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func|" ct/${script_name}.sh
|
||||
sed -i "s|https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func|https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func|" ct/${script_name}.sh
|
||||
@@ -204,6 +242,7 @@ jobs:
|
||||
;;
|
||||
vm)
|
||||
cp ../vm/${script_name}.sh vm/
|
||||
cp ../frontend/public/json/${script_name}.json frontend/public/json/ 2>/dev/null || true
|
||||
|
||||
# Update URLs in vm script
|
||||
sed -i "s|https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func|https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func|" vm/${script_name}.sh
|
||||
@@ -212,6 +251,7 @@ jobs:
|
||||
addon)
|
||||
mkdir -p tools/addon
|
||||
cp ../tools/addon/${script_name}.sh tools/addon/
|
||||
cp ../frontend/public/json/${script_name}.json frontend/public/json/ 2>/dev/null || true
|
||||
|
||||
# Update URLs in addon script
|
||||
sed -i "s|community-scripts/ProxmoxVED|community-scripts/ProxmoxVE|g" tools/addon/${script_name}.sh
|
||||
|
||||
39
.github/workflows/push-to-gitea.yml
generated
vendored
Normal file
39
.github/workflows/push-to-gitea.yml
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
name: Sync to Gitea
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
if: github.repository == 'community-scripts/ProxmoxVED'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout source repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set Git identity for actions
|
||||
run: |
|
||||
git config --global user.name "Push From Github"
|
||||
git config --global user.email "actions@github.com"
|
||||
- name: Add Gitea remote
|
||||
run: git remote add gitea https://$GITEA_USER:$GITEA_TOKEN@git.community-scripts.org/community-scripts/ProxmoxVED.git
|
||||
env:
|
||||
GITEA_USER: ${{ secrets.GITEA_USERNAME }}
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
- name: Pull Gitea changes
|
||||
run: |
|
||||
git fetch gitea
|
||||
git merge --strategy=ours gitea/main
|
||||
env:
|
||||
GITEA_USER: ${{ secrets.GITEA_USERNAME }}
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
|
||||
- name: Push to Gitea
|
||||
run: git push gitea main --force
|
||||
env:
|
||||
GITEA_USER: ${{ secrets.GITEA_USERNAME }}
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
82
.github/workflows/push_json_to_pocketbase.yml
generated
vendored
82
.github/workflows/push_json_to_pocketbase.yml
generated
vendored
@@ -1,12 +1,11 @@
|
||||
name: Push JSON changes to PocketBase
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
script_slug:
|
||||
description: 'Script slug (e.g. my-app)'
|
||||
required: true
|
||||
type: string
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "frontend/public/json/**"
|
||||
|
||||
jobs:
|
||||
push-json:
|
||||
@@ -17,23 +16,23 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get JSON file for script
|
||||
- name: Get changed JSON files with slug
|
||||
id: changed
|
||||
run: |
|
||||
script_slug="${{ github.event.inputs.script_slug }}"
|
||||
file="json/${script_slug}.json"
|
||||
if [[ ! -f "$file" ]]; then
|
||||
echo "No JSON file at $file."
|
||||
changed=$(git diff --name-only "${{ github.event.before }}" "${{ github.event.after }}" -- frontend/public/json/ | grep '\.json$' || true)
|
||||
with_slug=""
|
||||
for f in $changed; do
|
||||
[[ -f "$f" ]] || continue
|
||||
jq -e '.slug' "$f" >/dev/null 2>&1 && with_slug="$with_slug $f"
|
||||
done
|
||||
with_slug=$(echo $with_slug | xargs -n1)
|
||||
if [[ -z "$with_slug" ]]; then
|
||||
echo "No app JSON files changed (or no files with slug)."
|
||||
echo "count=0" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
if ! jq -e '.slug' "$file" >/dev/null 2>&1; then
|
||||
echo "File $file has no .slug."
|
||||
echo "count=0" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
echo "$file" > changed_app_jsons.txt
|
||||
echo "count=1" >> "$GITHUB_OUTPUT"
|
||||
echo "$with_slug" > changed_app_jsons.txt
|
||||
echo "count=$(echo "$with_slug" | wc -w)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Push to PocketBase
|
||||
if: steps.changed.outputs.count != '0'
|
||||
@@ -97,7 +96,7 @@ jobs:
|
||||
const recordsUrl = apiBase + '/collections/' + encodeURIComponent(coll) + '/records';
|
||||
let categoryIdToName = {};
|
||||
try {
|
||||
const metadata = JSON.parse(fs.readFileSync('json/metadata.json', 'utf8'));
|
||||
const metadata = JSON.parse(fs.readFileSync('frontend/public/json/metadata.json', 'utf8'));
|
||||
(metadata.categories || []).forEach(function(cat) { categoryIdToName[cat.id] = cat.name; });
|
||||
} catch (e) { console.warn('Could not load metadata.json:', e.message); }
|
||||
let typeValueToId = {};
|
||||
@@ -126,32 +125,22 @@ 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 } });
|
||||
if (res.ok) {
|
||||
(JSON.parse(res.body).items || []).forEach(function(item) {
|
||||
var osName = item.expand && item.expand.os && item.expand.os.os != null ? item.expand.os.os : null;
|
||||
if (osName != null && item.version != null) {
|
||||
var key = osName + '|' + item.version;
|
||||
osVersionToId[key] = item.id;
|
||||
osVersionToId[osName.toLowerCase() + '|' + item.version] = item.id;
|
||||
}
|
||||
if (osName != null && item.version != null) osVersionToId[osName + '|' + item.version] = item.id;
|
||||
});
|
||||
}
|
||||
} catch (e) { console.warn('z_ref_os_version:', e.message); }
|
||||
@@ -196,27 +185,23 @@ jobs:
|
||||
var noteIds = [];
|
||||
for (var i = 0; i < (data.notes || []).length; i++) {
|
||||
var note = data.notes[i];
|
||||
var typeId = noteTypeToId[note.type] || (note.type && noteTypeToId[note.type.toLowerCase()]);
|
||||
if (typeId == null) {
|
||||
console.warn('Note type not in z_ref_note_types:', note.type);
|
||||
continue;
|
||||
}
|
||||
var typeId = noteTypeToId[note.type];
|
||||
if (typeId == null) continue;
|
||||
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);
|
||||
else console.error('script_notes POST failed:', postRes.statusCode, postRes.body);
|
||||
}
|
||||
var installMethodIds = [];
|
||||
for (var j = 0; j < (data.install_methods || []).length; j++) {
|
||||
var im = data.install_methods[j];
|
||||
var typeId = installMethodTypeToId[im.type] || (im.type && installMethodTypeToId[im.type.toLowerCase()]);
|
||||
var typeId = installMethodTypeToId[im.type];
|
||||
var res = im.resources || {};
|
||||
var osId = osToId[res.os] || (res.os && osToId[res.os.toLowerCase()]);
|
||||
var osId = osToId[res.os];
|
||||
var osVersionKey = (res.os != null && res.version != null) ? res.os + '|' + res.version : null;
|
||||
var osVersionId = osVersionKey ? (osVersionToId[osVersionKey] || osVersionToId[res.os.toLowerCase() + '|' + res.version]) : null;
|
||||
var osVersionId = osVersionKey ? osVersionToId[osVersionKey] : null;
|
||||
var imBody = {
|
||||
script: scriptId,
|
||||
resources_cpu: res.cpu != null ? res.cpu : 0,
|
||||
@@ -232,7 +217,6 @@ jobs:
|
||||
body: JSON.stringify(imBody)
|
||||
});
|
||||
if (imPostRes.ok) installMethodIds.push(JSON.parse(imPostRes.body).id);
|
||||
else console.error('script_install_methods POST failed:', imPostRes.statusCode, imPostRes.body);
|
||||
}
|
||||
return { noteIds: noteIds, installMethodIds: installMethodIds };
|
||||
}
|
||||
@@ -241,7 +225,6 @@ jobs:
|
||||
payload.notes = resolved.noteIds;
|
||||
payload.install_methods = resolved.installMethodIds;
|
||||
console.log('Updating', file, '(slug=' + data.slug + ')');
|
||||
console.log('Created', resolved.noteIds.length, 'notes,', resolved.installMethodIds.length, 'install_methods for slug=' + data.slug);
|
||||
const r = await request(recordsUrl + '/' + existingId, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||
@@ -258,19 +241,12 @@ jobs:
|
||||
if (!r.ok) throw new Error('POST failed: ' + r.body);
|
||||
var scriptId = JSON.parse(r.body).id;
|
||||
var resolved = await resolveNotesAndInstallMethods(scriptId);
|
||||
console.log('Created', resolved.noteIds.length, 'notes,', resolved.installMethodIds.length, 'install_methods for slug=' + data.slug);
|
||||
var patchPayload = {};
|
||||
for (var k in payload) patchPayload[k] = payload[k];
|
||||
patchPayload.notes = resolved.noteIds;
|
||||
patchPayload.install_methods = resolved.installMethodIds;
|
||||
var patchRes = await request(recordsUrl + '/' + scriptId, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(patchPayload)
|
||||
body: JSON.stringify({ install_methods: resolved.installMethodIds, notes: resolved.noteIds })
|
||||
});
|
||||
if (!patchRes.ok) throw new Error('PATCH relations failed: ' + patchRes.body);
|
||||
var patched = JSON.parse(patchRes.body);
|
||||
console.log('Script linked: notes=' + (patched.notes && patched.notes.length) + ', install_methods=' + (patched.install_methods && patched.install_methods.length));
|
||||
}
|
||||
}
|
||||
console.log('Done.');
|
||||
|
||||
2
.github/workflows/scripts/get-gh-release.sh
generated
vendored
2
.github/workflows/scripts/get-gh-release.sh
generated
vendored
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
INPUT_FILE=".github/workflows/scripts/repos.txt"
|
||||
OUTPUT_FILE="json/versions.json"
|
||||
OUTPUT_FILE="frontend/public/json/versions.json"
|
||||
TMP_FILE="releases_tmp.json"
|
||||
|
||||
if [ -f "$OUTPUT_FILE" ]; then
|
||||
|
||||
41
.github/workflows/trigger_github_pages_redirect.yml
generated
vendored
41
.github/workflows/trigger_github_pages_redirect.yml
generated
vendored
@@ -1,41 +0,0 @@
|
||||
name: Pages Redirect
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
pages: write
|
||||
id-token: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create redirect page
|
||||
run: |
|
||||
mkdir site
|
||||
cat <<EOF > site/index.html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=https://community-scripts.org/">
|
||||
<link rel="canonical" href="https://community-scripts.org/">
|
||||
<title>Redirecting...</title>
|
||||
</head>
|
||||
<body>
|
||||
Redirecting...
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
|
||||
- uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: site
|
||||
|
||||
- name: Deploy
|
||||
uses: actions/deploy-pages@v4
|
||||
89
.github/workflows/unmet-pr-close.yml
generated
vendored
89
.github/workflows/unmet-pr-close.yml
generated
vendored
@@ -1,89 +0,0 @@
|
||||
name: PR Script Requirements Check
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, edited, synchronize]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
validate-script-requirements:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Validate new script requirements
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const body = context.payload.pull_request.body || "";
|
||||
const lines = body.split("\n");
|
||||
|
||||
function checkboxChecked(line) {
|
||||
return /\[\s*x\s*\]/i.test(line);
|
||||
}
|
||||
|
||||
function findLine(text) {
|
||||
return lines.find(l => l.includes(text));
|
||||
}
|
||||
|
||||
// detect if "New script" is checked
|
||||
const newScriptLine = findLine("🆕 **New script**");
|
||||
if (!newScriptLine || !checkboxChecked(newScriptLine)) {
|
||||
console.log("Not a new script PR — skipping requirement check.");
|
||||
return;
|
||||
}
|
||||
|
||||
const requirements = [
|
||||
"The application is **at least 6 months old**",
|
||||
"The application is **actively maintained**",
|
||||
"The application has **600+ GitHub stars**",
|
||||
"Official **release tarballs** are published",
|
||||
"I understand that not all scripts will be accepted"
|
||||
];
|
||||
|
||||
const missing = [];
|
||||
|
||||
for (const req of requirements) {
|
||||
const line = findLine(req);
|
||||
if (!line || !checkboxChecked(line)) {
|
||||
missing.push(req);
|
||||
}
|
||||
}
|
||||
|
||||
if (missing.length > 0) {
|
||||
|
||||
let list = "";
|
||||
for (const m of missing) {
|
||||
list += "- " + m + "\n";
|
||||
}
|
||||
|
||||
const message =
|
||||
"❌ **Pull Request Closed – Application Requirements Not Met**\n\n" +
|
||||
"This pull request is marked as **🆕 New script**, but the required application criteria were not confirmed.\n\n" +
|
||||
"The following requirement confirmations are missing:\n\n" +
|
||||
list +
|
||||
"\nNew application submissions must meet the project requirements before being considered.\n" +
|
||||
"Please wait until the application satisfies the criteria before submitting a new PR.\n\n" +
|
||||
"---\n\n" +
|
||||
"⚠ **Maintainer note**\n\n" +
|
||||
"The team periodically reviews closed submissions. If a project is still considered valuable to the ecosystem, maintainers may reopen the PR even if it does not fully meet the thresholds.\n\n" +
|
||||
"**Please do not ping or repeatedly contact maintainers to reopen PRs.**";
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
body: message
|
||||
});
|
||||
|
||||
await github.rest.pulls.update({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: context.issue.number,
|
||||
state: "closed"
|
||||
});
|
||||
|
||||
core.setFailed("Application requirements checklist incomplete.");
|
||||
}
|
||||
218
.github/workflows/update-github-versions.yml
generated
vendored
Normal file
218
.github/workflows/update-github-versions.yml
generated
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
name: Update GitHub Versions (New)
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# Runs 4x daily: 00:00, 06:00, 12:00, 18:00 UTC
|
||||
- cron: "0 0,6,12,18 * * *"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
env:
|
||||
VERSIONS_FILE: frontend/public/json/github-versions.json
|
||||
|
||||
jobs:
|
||||
update-github-versions:
|
||||
if: github.repository == 'community-scripts/ProxmoxVED'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: main
|
||||
|
||||
- name: Extract GitHub versions from install scripts
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
echo "========================================="
|
||||
echo " Extracting GitHub versions from scripts"
|
||||
echo "========================================="
|
||||
|
||||
# Initialize versions array
|
||||
versions_json="[]"
|
||||
|
||||
# Function to add a version entry
|
||||
add_version() {
|
||||
local slug="$1"
|
||||
local repo="$2"
|
||||
local version="$3"
|
||||
local pinned="$4"
|
||||
local date="$5"
|
||||
|
||||
versions_json=$(echo "$versions_json" | jq \
|
||||
--arg slug "$slug" \
|
||||
--arg repo "$repo" \
|
||||
--arg version "$version" \
|
||||
--argjson pinned "$pinned" \
|
||||
--arg date "$date" \
|
||||
'. += [{"slug": $slug, "repo": $repo, "version": $version, "pinned": $pinned, "date": $date}]')
|
||||
}
|
||||
|
||||
# Get list of slugs from JSON files
|
||||
echo ""
|
||||
echo "=== Scanning JSON files for slugs ==="
|
||||
|
||||
for json_file in frontend/public/json/*.json; do
|
||||
[[ ! -f "$json_file" ]] && continue
|
||||
|
||||
# Skip non-app JSON files
|
||||
basename_file=$(basename "$json_file")
|
||||
case "$basename_file" in
|
||||
metadata.json|versions.json|github-versions.json|dependency-check.json|update-apps.json)
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
|
||||
# Extract slug from JSON
|
||||
slug=$(jq -r '.slug // empty' "$json_file" 2>/dev/null)
|
||||
[[ -z "$slug" ]] && continue
|
||||
|
||||
# Find corresponding install script
|
||||
install_script="install/${slug}-install.sh"
|
||||
[[ ! -f "$install_script" ]] && continue
|
||||
|
||||
# Look for fetch_and_deploy_gh_release calls
|
||||
# Pattern: fetch_and_deploy_gh_release "app" "owner/repo" ["mode"] ["version"]
|
||||
while IFS= read -r line; do
|
||||
# Skip commented lines
|
||||
[[ "$line" =~ ^[[:space:]]*# ]] && continue
|
||||
|
||||
# Extract repo and version from fetch_and_deploy_gh_release
|
||||
if [[ "$line" =~ fetch_and_deploy_gh_release[[:space:]]+\"[^\"]*\"[[:space:]]+\"([^\"]+)\"([[:space:]]+\"([^\"]+)\")?([[:space:]]+\"([^\"]+)\")? ]]; then
|
||||
repo="${BASH_REMATCH[1]}"
|
||||
mode="${BASH_REMATCH[3]:-tarball}"
|
||||
pinned_version="${BASH_REMATCH[5]:-latest}"
|
||||
|
||||
# Check if version is pinned (not "latest" and not empty)
|
||||
is_pinned=false
|
||||
target_version=""
|
||||
|
||||
if [[ -n "$pinned_version" && "$pinned_version" != "latest" ]]; then
|
||||
is_pinned=true
|
||||
target_version="$pinned_version"
|
||||
fi
|
||||
|
||||
# Fetch version from GitHub
|
||||
if [[ "$is_pinned" == "true" ]]; then
|
||||
# For pinned versions, verify it exists and get date
|
||||
response=$(gh api "repos/${repo}/releases/tags/${target_version}" 2>/dev/null || echo '{}')
|
||||
if echo "$response" | jq -e '.tag_name' > /dev/null 2>&1; then
|
||||
version=$(echo "$response" | jq -r '.tag_name')
|
||||
date=$(echo "$response" | jq -r '.published_at // empty')
|
||||
add_version "$slug" "$repo" "$version" "true" "$date"
|
||||
echo "[$slug] ✓ $version (pinned)"
|
||||
else
|
||||
echo "[$slug] ⚠ pinned version $target_version not found"
|
||||
fi
|
||||
else
|
||||
# Fetch latest release
|
||||
response=$(gh api "repos/${repo}/releases/latest" 2>/dev/null || echo '{}')
|
||||
if echo "$response" | jq -e '.tag_name' > /dev/null 2>&1; then
|
||||
version=$(echo "$response" | jq -r '.tag_name')
|
||||
date=$(echo "$response" | jq -r '.published_at // empty')
|
||||
add_version "$slug" "$repo" "$version" "false" "$date"
|
||||
echo "[$slug] ✓ $version"
|
||||
else
|
||||
# Try tags as fallback
|
||||
version=$(gh api "repos/${repo}/tags" --jq '.[0].name // empty' 2>/dev/null || echo "")
|
||||
if [[ -n "$version" ]]; then
|
||||
add_version "$slug" "$repo" "$version" "false" ""
|
||||
echo "[$slug] ✓ $version (from tags)"
|
||||
else
|
||||
echo "[$slug] ⚠ no version found"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
break # Only first match per script
|
||||
fi
|
||||
done < <(grep 'fetch_and_deploy_gh_release' "$install_script" 2>/dev/null || true)
|
||||
|
||||
done
|
||||
|
||||
# Save versions file
|
||||
echo "$versions_json" | jq --arg date "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
||||
'{generated: $date, versions: (. | sort_by(.slug))}' > "$VERSIONS_FILE"
|
||||
|
||||
total=$(echo "$versions_json" | jq 'length')
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo " Total versions extracted: $total"
|
||||
echo "========================================="
|
||||
|
||||
- name: Check for changes
|
||||
id: check-changes
|
||||
run: |
|
||||
# Check if file is new (untracked) or has changes
|
||||
if [[ ! -f "$VERSIONS_FILE" ]]; then
|
||||
echo "changed=false" >> "$GITHUB_OUTPUT"
|
||||
echo "Versions file was not created"
|
||||
elif ! git ls-files --error-unmatch "$VERSIONS_FILE" &>/dev/null; then
|
||||
# File exists but is not tracked - it's new
|
||||
echo "changed=true" >> "$GITHUB_OUTPUT"
|
||||
echo "New file created: $VERSIONS_FILE"
|
||||
elif git diff --quiet "$VERSIONS_FILE" 2>/dev/null; then
|
||||
echo "changed=false" >> "$GITHUB_OUTPUT"
|
||||
echo "No changes detected"
|
||||
else
|
||||
echo "changed=true" >> "$GITHUB_OUTPUT"
|
||||
echo "Changes detected:"
|
||||
git diff --stat "$VERSIONS_FILE" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
- name: Create Pull Request
|
||||
if: steps.check-changes.outputs.changed == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
BRANCH_NAME="automated/update-github-versions-$(date +%Y%m%d)"
|
||||
|
||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --global user.name "GitHub Actions[bot]"
|
||||
|
||||
# Check if branch exists and delete it
|
||||
git push origin --delete "$BRANCH_NAME" 2>/dev/null || true
|
||||
|
||||
git checkout -b "$BRANCH_NAME"
|
||||
git add "$VERSIONS_FILE"
|
||||
git commit -m "chore: update github-versions.json
|
||||
|
||||
Total versions: $(jq '.versions | length' "$VERSIONS_FILE")
|
||||
Pinned versions: $(jq '[.versions[] | select(.pinned == true)] | length' "$VERSIONS_FILE")
|
||||
Generated: $(jq -r '.generated' "$VERSIONS_FILE")"
|
||||
|
||||
git push origin "$BRANCH_NAME" --force
|
||||
|
||||
# Check if PR already exists
|
||||
existing_pr=$(gh pr list --head "$BRANCH_NAME" --state open --json number --jq '.[0].number // empty')
|
||||
|
||||
if [[ -n "$existing_pr" ]]; then
|
||||
echo "PR #$existing_pr already exists, updating..."
|
||||
else
|
||||
gh pr create \
|
||||
--title "[Automated] Update GitHub versions" \
|
||||
--body "This PR updates version information from GitHub releases.
|
||||
|
||||
## How it works
|
||||
1. Scans all JSON files in \`frontend/public/json/\` for slugs
|
||||
2. Finds corresponding \`install/{slug}-install.sh\` scripts
|
||||
3. Extracts \`fetch_and_deploy_gh_release\` calls
|
||||
4. Fetches latest (or pinned) version from GitHub
|
||||
|
||||
## Stats
|
||||
- Total versions: $(jq '.versions | length' "$VERSIONS_FILE")
|
||||
- Pinned versions: $(jq '[.versions[] | select(.pinned == true)] | length' "$VERSIONS_FILE")
|
||||
- Latest versions: $(jq '[.versions[] | select(.pinned == false)] | length' "$VERSIONS_FILE")
|
||||
|
||||
---
|
||||
*Automatically generated from install scripts*" \
|
||||
--base main \
|
||||
--head "$BRANCH_NAME" \
|
||||
--label "automated pr"
|
||||
fi
|
||||
167
.github/workflows/update-timestamp-on-db.yml
generated
vendored
167
.github/workflows/update-timestamp-on-db.yml
generated
vendored
@@ -1,167 +0,0 @@
|
||||
name: Update script timestamp on .sh changes
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "ct/**/*.sh"
|
||||
- "install/**/*.sh"
|
||||
- "tools/**/*.sh"
|
||||
- "turnkey/**/*.sh"
|
||||
- "vm/**/*.sh"
|
||||
|
||||
jobs:
|
||||
update-script-timestamp:
|
||||
runs-on: self-hosted
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get changed .sh files and derive slugs
|
||||
id: slugs
|
||||
run: |
|
||||
changed=$(git diff --name-only "${{ github.event.before }}" "${{ github.event.after }}" -- ct/ install/ tools/ turnkey/ vm/ | grep '\.sh$' || true)
|
||||
if [[ -z "$changed" ]]; then
|
||||
echo "No .sh files changed in ct/, install/, tools/, turnkey/, or vm/."
|
||||
echo "count=0" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
declare -A seen
|
||||
slugs=""
|
||||
for f in $changed; do
|
||||
[[ -f "$f" ]] || continue
|
||||
base="${f##*/}"
|
||||
base="${base%.sh}"
|
||||
if [[ "$f" == install/* && "$base" == *-install ]]; then
|
||||
slug="${base%-install}"
|
||||
else
|
||||
slug="$base"
|
||||
fi
|
||||
if [[ -z "${seen[$slug]:-}" ]]; then
|
||||
seen[$slug]=1
|
||||
slugs="$slugs $slug"
|
||||
fi
|
||||
done
|
||||
slugs=$(echo $slugs | xargs -n1 | sort -u)
|
||||
if [[ -z "$slugs" ]]; then
|
||||
echo "No slugs to update."
|
||||
echo "count=0" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
echo "$slugs" > changed_slugs.txt
|
||||
echo "count=$(echo "$slugs" | wc -w)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Parse PR number from merge commit
|
||||
id: pr
|
||||
run: |
|
||||
re='#([0-9]+)'
|
||||
if [[ "$COMMIT_MSG" =~ $re ]]; then
|
||||
echo "number=${BASH_REMATCH[1]}" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "number=" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
env:
|
||||
COMMIT_MSG: ${{ github.event.head_commit.message }}
|
||||
|
||||
- name: Update script timestamps in PocketBase
|
||||
if: steps.slugs.outputs.count != '0'
|
||||
env:
|
||||
POCKETBASE_URL: ${{ secrets.POCKETBASE_URL }}
|
||||
POCKETBASE_COLLECTION: ${{ secrets.POCKETBASE_COLLECTION }}
|
||||
POCKETBASE_ADMIN_EMAIL: ${{ secrets.POCKETBASE_ADMIN_EMAIL }}
|
||||
POCKETBASE_ADMIN_PASSWORD: ${{ secrets.POCKETBASE_ADMIN_PASSWORD }}
|
||||
COMMIT_URL: ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}
|
||||
PR_URL: ${{ steps.pr.outputs.number != '' && format('{0}/{1}/pull/{2}', github.server_url, github.repository, steps.pr.outputs.number) || '' }}
|
||||
run: |
|
||||
node << 'ENDSCRIPT'
|
||||
(async function() {
|
||||
const fs = require('fs');
|
||||
const https = require('https');
|
||||
const http = require('http');
|
||||
const url = require('url');
|
||||
|
||||
function request(fullUrl, opts) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
const u = url.parse(fullUrl);
|
||||
const isHttps = u.protocol === 'https:';
|
||||
const body = opts.body;
|
||||
const options = {
|
||||
hostname: u.hostname,
|
||||
port: u.port || (isHttps ? 443 : 80),
|
||||
path: u.path,
|
||||
method: opts.method || 'GET',
|
||||
headers: opts.headers || {}
|
||||
};
|
||||
if (body) options.headers['Content-Length'] = Buffer.byteLength(body);
|
||||
const lib = isHttps ? https : http;
|
||||
const req = lib.request(options, function(res) {
|
||||
let data = '';
|
||||
res.on('data', function(chunk) { data += chunk; });
|
||||
res.on('end', function() {
|
||||
resolve({ ok: res.statusCode >= 200 && res.statusCode < 300, statusCode: res.statusCode, body: data });
|
||||
});
|
||||
});
|
||||
req.on('error', reject);
|
||||
if (body) req.write(body);
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
const raw = process.env.POCKETBASE_URL.replace(/\/$/, '');
|
||||
const apiBase = /\/api$/i.test(raw) ? raw : raw + '/api';
|
||||
const coll = process.env.POCKETBASE_COLLECTION;
|
||||
const slugsText = fs.readFileSync('changed_slugs.txt', 'utf8').trim();
|
||||
const slugs = slugsText ? slugsText.split(/\s+/).filter(Boolean) : [];
|
||||
if (slugs.length === 0) {
|
||||
console.log('No slugs to update.');
|
||||
return;
|
||||
}
|
||||
|
||||
const authUrl = apiBase + '/collections/users/auth-with-password';
|
||||
const authBody = JSON.stringify({
|
||||
identity: process.env.POCKETBASE_ADMIN_EMAIL,
|
||||
password: process.env.POCKETBASE_ADMIN_PASSWORD
|
||||
});
|
||||
const authRes = await request(authUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: authBody
|
||||
});
|
||||
if (!authRes.ok) {
|
||||
throw new Error('Auth failed: ' + authRes.body);
|
||||
}
|
||||
const token = JSON.parse(authRes.body).token;
|
||||
const recordsUrl = apiBase + '/collections/' + encodeURIComponent(coll) + '/records';
|
||||
|
||||
for (const slug of slugs) {
|
||||
const filter = "(slug='" + slug.replace(/'/g, "''") + "')";
|
||||
const listRes = await request(recordsUrl + '?filter=' + encodeURIComponent(filter) + '&perPage=1', {
|
||||
headers: { 'Authorization': token }
|
||||
});
|
||||
const list = JSON.parse(listRes.body);
|
||||
const record = list.items && list.items[0];
|
||||
if (!record) {
|
||||
console.log('Slug not in DB, skipping: ' + slug);
|
||||
continue;
|
||||
}
|
||||
const patchRes = await request(recordsUrl + '/' + record.id, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
name: record.name || record.slug,
|
||||
last_update_commit: process.env.PR_URL || process.env.COMMIT_URL || ''
|
||||
})
|
||||
});
|
||||
if (!patchRes.ok) {
|
||||
console.warn('PATCH failed for slug ' + slug + ': ' + patchRes.body);
|
||||
continue;
|
||||
}
|
||||
console.log('Updated timestamp for slug: ' + slug);
|
||||
}
|
||||
console.log('Done.');
|
||||
})().catch(e => { console.error(e); process.exit(1); });
|
||||
ENDSCRIPT
|
||||
shell: bash
|
||||
@@ -1,75 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: Slaviša Arežina (tremor021)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||
# Source: https://wakapi.dev/ | https://github.com/muety/wakapi
|
||||
|
||||
APP="Alpine-Wakapi"
|
||||
var_tags="${var_tags:-code;time-tracking}"
|
||||
var_cpu="${var_cpu:-1}"
|
||||
var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-4}"
|
||||
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 /opt/wakapi ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
RELEASE=$(curl -s https://api.github.com/repos/muety/wakapi/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')
|
||||
if [ "${RELEASE}" != "$(cat ~/.wakapi 2>/dev/null)" ] || [ ! -f ~/.wakapi ]; then
|
||||
msg_info "Stopping Wakapi Service"
|
||||
$STD rc-service wakapi stop
|
||||
msg_ok "Stopped Wakapi Service"
|
||||
|
||||
msg_info "Updating Wakapi LXC"
|
||||
$STD apk -U upgrade
|
||||
msg_ok "Updated Wakapi LXC"
|
||||
|
||||
msg_info "Creating backup"
|
||||
mkdir -p /opt/wakapi-backup
|
||||
cp /opt/wakapi/config.yml /opt/wakapi/wakapi_db.db /opt/wakapi-backup/
|
||||
msg_ok "Created backup"
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "wakapi" "muety/wakapi" "tarball"
|
||||
|
||||
msg_info "Configuring Wakapi"
|
||||
cd /opt/wakapi
|
||||
$STD go mod download
|
||||
$STD go build -o wakapi
|
||||
cp /opt/wakapi-backup/config.yml /opt/wakapi/
|
||||
cp /opt/wakapi-backup/wakapi_db.db /opt/wakapi/
|
||||
rm -rf /opt/wakapi-backup
|
||||
msg_ok "Configured Wakapi"
|
||||
|
||||
msg_info "Starting Service"
|
||||
$STD rc-service wakapi start
|
||||
msg_ok "Started Service"
|
||||
msg_ok "Updated successfully"
|
||||
else
|
||||
msg_ok "No update required. ${APP} is already at ${RELEASE}"
|
||||
fi
|
||||
exit 0
|
||||
}
|
||||
|
||||
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}"
|
||||
67
ct/anytype-server.sh
Normal file
67
ct/anytype-server.sh
Normal file
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVED/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,41 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/asylumexp/Proxmox/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 tteck
|
||||
# Author: tteck (tteckster)
|
||||
# License: MIT | https://github.com/asylumexp/Proxmox/raw/main/LICENSE
|
||||
# Source: https://adguard.com/
|
||||
|
||||
APP="Adguard"
|
||||
var_tags="${var_tags:-adblock}"
|
||||
var_cpu="${var_cpu:-1}"
|
||||
var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-2}"
|
||||
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/AdGuardHome ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
msg_error "Adguard Home can only be updated via the user interface."
|
||||
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}"
|
||||
@@ -1,70 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/asylumexp/Proxmox/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 tteck
|
||||
# Author: tteck (tteckster)
|
||||
# License: MIT | https://github.com/asylumexp/Proxmox/raw/main/LICENSE
|
||||
# Source: https://www.bazarr.media/
|
||||
|
||||
APP="Bazarr"
|
||||
var_tags="${var_tags:-arr}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-1024}"
|
||||
var_disk="${var_disk:-4}"
|
||||
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 /var/lib/bazarr/ ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
if check_for_gh_release "bazarr" "morpheus65535/bazarr"; then
|
||||
apt-get install -y libicu76 &>/dev/null
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop bazarr
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
PYTHON_VERSION="3.12" setup_uv
|
||||
fetch_and_deploy_gh_release "bazarr" "morpheus65535/bazarr" "prebuild" "latest" "/opt/bazarr" "bazarr.zip"
|
||||
|
||||
msg_info "Setup Bazarr"
|
||||
mkdir -p /var/lib/bazarr/
|
||||
chmod 775 /opt/bazarr /var/lib/bazarr/
|
||||
# Always ensure venv exists
|
||||
if [[ ! -d /opt/bazarr/venv/ ]]; then
|
||||
$STD uv venv --clear /opt/bazarr/venv --python 3.12
|
||||
fi
|
||||
|
||||
# Always check and fix service file if needed
|
||||
if [[ -f /etc/systemd/system/bazarr.service ]] && grep -q "ExecStart=/usr/bin/python3" /etc/systemd/system/bazarr.service; then
|
||||
sed -i "s|ExecStart=/usr/bin/python3 /opt/bazarr/bazarr.py|ExecStart=/opt/bazarr/venv/bin/python3 /opt/bazarr/bazarr.py|g" /etc/systemd/system/bazarr.service
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
sed -i.bak 's/--only-binary=Pillow//g' /opt/bazarr/requirements.txt
|
||||
$STD uv pip install -r /opt/bazarr/requirements.txt --python /opt/bazarr/venv/bin/python3
|
||||
msg_ok "Setup Bazarr"
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start bazarr
|
||||
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}:6767${CL}"
|
||||
@@ -1,62 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/asylumexp/Proxmox/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: vhsdream
|
||||
# License: MIT | https://github.com/asylumexp/Proxmox/raw/main/LICENSE
|
||||
# Source: https://github.com/alam00000/bentopdf
|
||||
|
||||
APP="BentoPDF"
|
||||
var_tags="${var_tags:-pdf-editor}"
|
||||
var_cpu="${var_cpu:-1}"
|
||||
var_ram="${var_ram:-4096}"
|
||||
var_disk="${var_disk:-4}"
|
||||
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/bentopdf ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
NODE_VERSION="24" setup_nodejs
|
||||
|
||||
if check_for_gh_release "bentopdf" "alam00000/bentopdf"; then
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop bentopdf
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "bentopdf" "alam00000/bentopdf" "tarball" "latest" "/opt/bentopdf"
|
||||
|
||||
msg_info "Updating BentoPDF"
|
||||
cd /opt/bentopdf
|
||||
$STD npm ci --no-audit --no-fund
|
||||
export SIMPLE_MODE=true
|
||||
$STD npm run build -- --mode production
|
||||
msg_ok "Updated BentoPDF"
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start bentopdf
|
||||
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}:8080${CL}"
|
||||
@@ -1,109 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/asylumexp/Proxmox/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 tteck
|
||||
# Author: tteck (tteckster)
|
||||
# License: MIT | https://github.com/asylumexp/Proxmox/raw/main/LICENSE
|
||||
# Source: https://www.home-assistant.io/
|
||||
|
||||
APP="Home Assistant"
|
||||
var_tags="${var_tags:-automation;smarthome}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-16}"
|
||||
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 /var/lib/docker/volumes/hass_config/_data ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
UPD=$(msg_menu "Home Assistant Update Options" \
|
||||
"1" "Update ALL Containers" \
|
||||
"2" "Remove ALL Unused Images" \
|
||||
"3" "Install HACS" \
|
||||
"4" "Install FileBrowser")
|
||||
|
||||
if [ "$UPD" == "1" ]; then
|
||||
msg_info "Updating All Containers"
|
||||
CONTAINER_LIST="${1:-$(docker ps -q)}"
|
||||
for container in ${CONTAINER_LIST}; do
|
||||
CONTAINER_IMAGE="$(docker inspect --format "{{.Config.Image}}" --type container "${container}")"
|
||||
RUNNING_IMAGE="$(docker inspect --format "{{.Image}}" --type container "${container}")"
|
||||
docker pull "${CONTAINER_IMAGE}"
|
||||
LATEST_IMAGE="$(docker inspect --format "{{.Id}}" --type image "${CONTAINER_IMAGE}")"
|
||||
if [[ "${RUNNING_IMAGE}" != "${LATEST_IMAGE}" ]]; then
|
||||
pip install -U runlike
|
||||
echo "Updating ${container} image ${CONTAINER_IMAGE}"
|
||||
DOCKER_COMMAND="$(runlike --use-volume-id "${container}")"
|
||||
docker rm --force "${container}"
|
||||
eval "${DOCKER_COMMAND}"
|
||||
fi
|
||||
done
|
||||
msg_ok "Updated All Containers"
|
||||
exit
|
||||
fi
|
||||
if [ "$UPD" == "2" ]; then
|
||||
msg_info "Removing ALL Unused Images"
|
||||
docker image prune -af
|
||||
msg_ok "Removed ALL Unused Images"
|
||||
exit
|
||||
fi
|
||||
if [ "$UPD" == "3" ]; then
|
||||
msg_info "Installing Home Assistant Community Store (HACS)"
|
||||
$STD apt update
|
||||
cd /var/lib/docker/volumes/hass_config/_data
|
||||
$STD bash <(curl -fsSL https://get.hacs.xyz)
|
||||
msg_ok "Installed Home Assistant Community Store (HACS)"
|
||||
echo -e "\n Reboot Home Assistant and clear browser cache then Add HACS integration.\n"
|
||||
exit
|
||||
fi
|
||||
if [ "$UPD" == "4" ]; then
|
||||
msg_info "Installing FileBrowser"
|
||||
RELEASE=$(curl -fsSL https://api.github.com/repos/filebrowser/filebrowser/releases/latest | grep -o '"tag_name": ".*"' | sed 's/"//g' | sed 's/tag_name: //g')
|
||||
$STD curl -fsSL https://github.com/filebrowser/filebrowser/releases/download/v2.23.0/linux-arm64-filebrowser.tar.gz | tar -xzv -C /usr/local/bin
|
||||
$STD filebrowser config init -a '0.0.0.0'
|
||||
$STD filebrowser config set -a '0.0.0.0'
|
||||
$STD filebrowser users add admin helper-scripts.com --perm.admin
|
||||
msg_ok "Installed FileBrowser"
|
||||
|
||||
msg_info "Creating Service"
|
||||
service_path="/etc/systemd/system/filebrowser.service"
|
||||
echo "[Unit]
|
||||
Description=Filebrowser
|
||||
After=network-online.target
|
||||
[Service]
|
||||
User=root
|
||||
WorkingDirectory=/root/
|
||||
ExecStart=/usr/local/bin/filebrowser -r /
|
||||
[Install]
|
||||
WantedBy=default.target" >$service_path
|
||||
|
||||
$STD systemctl enable --now filebrowser
|
||||
msg_ok "Created Service"
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "FileBrowser should be reachable by going to the following URL.
|
||||
${BL}http://$LOCAL_IP:8080${CL} admin|helper-scripts.com\n"
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
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}HA: http://${IP}:8123${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}Portainer: https://${IP}:9443${CL}"
|
||||
@@ -1,52 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/asylumexp/Proxmox/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 tteck
|
||||
# Author: tteck (tteckster)
|
||||
# License: MIT | https://github.com/asylumexp/Proxmox/raw/main/LICENSE
|
||||
# Source: https://jellyfin.org/
|
||||
|
||||
APP="Jellyfin"
|
||||
var_tags="${var_tags:-media}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-16}"
|
||||
var_os="${var_os:-ubuntu}"
|
||||
var_version="${var_version:-24.04}"
|
||||
var_unprivileged="${var_unprivileged:-0}"
|
||||
var_gpu="${var_gpu:-yes}"
|
||||
|
||||
header_info "$APP"
|
||||
variables
|
||||
color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
if [[ ! -d /usr/lib/jellyfin ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
msg_info "Updating Jellyfin"
|
||||
ensure_dependencies libjemalloc2
|
||||
if [[ ! -f /usr/lib/libjemalloc.so ]]; then
|
||||
ln -sf /usr/lib/aarch64-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
|
||||
msg_ok "Updated Jellyfin"
|
||||
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}:8096${CL}"
|
||||
@@ -1,79 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/asylumexp/Proxmox/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/asylumexp/Proxmox/raw/main/LICENSE
|
||||
# Source: https://github.com/Chevron7Locked/kima-hub
|
||||
|
||||
APP="Kima-Hub"
|
||||
var_tags="${var_tags:-music;streaming;media}"
|
||||
var_cpu="${var_cpu:-4}"
|
||||
var_ram="${var_ram:-8192}"
|
||||
var_disk="${var_disk:-20}"
|
||||
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/kima-hub ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if check_for_gh_release "kima-hub" "Chevron7Locked/kima-hub"; then
|
||||
msg_info "Stopping Services"
|
||||
systemctl stop kima-frontend kima-backend kima-analyzer kima-analyzer-clap
|
||||
msg_ok "Stopped Services"
|
||||
|
||||
msg_info "Backing up Data"
|
||||
cp /opt/kima-hub/backend/.env /opt/kima-hub-backend-env.bak
|
||||
cp /opt/kima-hub/frontend/.env /opt/kima-hub-frontend-env.bak
|
||||
msg_ok "Backed up Data"
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "kima-hub" "Chevron7Locked/kima-hub" "tarball"
|
||||
|
||||
msg_info "Restoring Data"
|
||||
cp /opt/kima-hub-backend-env.bak /opt/kima-hub/backend/.env
|
||||
cp /opt/kima-hub-frontend-env.bak /opt/kima-hub/frontend/.env
|
||||
rm -f /opt/kima-hub-backend-env.bak /opt/kima-hub-frontend-env.bak
|
||||
msg_ok "Restored Data"
|
||||
|
||||
msg_info "Rebuilding Backend"
|
||||
cd /opt/kima-hub/backend
|
||||
$STD npm install
|
||||
$STD npm run build
|
||||
$STD npx prisma generate
|
||||
$STD npx prisma migrate deploy
|
||||
msg_ok "Rebuilt Backend"
|
||||
|
||||
msg_info "Rebuilding Frontend"
|
||||
cd /opt/kima-hub/frontend
|
||||
$STD npm install
|
||||
$STD npm run build
|
||||
msg_ok "Rebuilt Frontend"
|
||||
|
||||
msg_info "Starting Services"
|
||||
systemctl start kima-backend kima-frontend kima-analyzer kima-analyzer-clap
|
||||
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}:3030${CL}"
|
||||
@@ -1,74 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/asylumexp/Proxmox/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: kristocopani
|
||||
# License: MIT | https://github.com/asylumexp/Proxmox/raw/main/LICENSE
|
||||
# Source: https://lubelogger.com/
|
||||
|
||||
APP="LubeLogger"
|
||||
var_tags="${var_tags:-vehicle;car}"
|
||||
var_cpu="${var_cpu:-1}"
|
||||
var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-2}"
|
||||
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 [[ ! -f /etc/systemd/system/lubelogger.service ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
if check_for_gh_release "lubelogger" "hargata/lubelog"; then
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop lubelogger
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
msg_info "Backing up data"
|
||||
mkdir -p /tmp/lubeloggerData/data
|
||||
cp /opt/lubelogger/appsettings.json /tmp/lubeloggerData/appsettings.json
|
||||
cp -r /opt/lubelogger/data/ /tmp/lubeloggerData/
|
||||
|
||||
# Lubelogger has moved multiples folders to the 'data' folder, and we need to move them before the update to keep the user data
|
||||
# Github Discussion: https://github.com/hargata/lubelog/discussions/787
|
||||
[[ -e /opt/lubelogger/config ]] && cp -r /opt/lubelogger/config /tmp/lubeloggerData/data/
|
||||
[[ -e /opt/lubelogger/wwwroot/translations ]] && cp -r /opt/lubelogger/wwwroot/translations /tmp/lubeloggerData/data/
|
||||
[[ -e /opt/lubelogger/wwwroot/documents ]] && cp -r /opt/lubelogger/wwwroot/documents /tmp/lubeloggerData/data/
|
||||
[[ -e /opt/lubelogger/wwwroot/images ]] && cp -r /opt/lubelogger/wwwroot/images /tmp/lubeloggerData/data/
|
||||
[[ -e /opt/lubelogger/wwwroot/temp ]] && cp -r /opt/lubelogger/wwwroot/temp /tmp/lubeloggerData/data/
|
||||
[[ -e /opt/lubelogger/log ]] && cp -r /opt/lubelogger/log /tmp/lubeloggerData/
|
||||
rm -rf /opt/lubelogger
|
||||
msg_ok "Backed up data"
|
||||
|
||||
fetch_and_deploy_gh_release "lubelogger" "hargata/lubelog" "prebuild" "latest" "/opt/lubelogger" "LubeLogger*linux_x64.zip"
|
||||
|
||||
msg_info "Configuring LubeLogger"
|
||||
chmod 700 /opt/lubelogger/CarCareTracker
|
||||
cp -rf /tmp/lubeloggerData/* /opt/lubelogger/
|
||||
rm -rf /tmp/lubeloggerData
|
||||
msg_ok "Configured LubeLogger"
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start lubelogger
|
||||
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}:5000${CL}"
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/asylumexp/Proxmox/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 tteck
|
||||
# Author: tteck (tteckster)
|
||||
# License: MIT | https://github.com/asylumexp/Proxmox/raw/main/LICENSE
|
||||
# Source: https://pi-hole.net/
|
||||
|
||||
APP="Pihole"
|
||||
var_tags="${var_tags:-adblock}"
|
||||
var_cpu="${var_cpu:-1}"
|
||||
var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-2}"
|
||||
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 /etc/pihole ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
msg_info "Updating PiHole"
|
||||
set +e
|
||||
$STD apt update
|
||||
$STD apt upgrade -y
|
||||
/usr/local/bin/pihole -up
|
||||
msg_ok "Updated PiHole"
|
||||
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}/admin${CL}"
|
||||
@@ -1,63 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/asylumexp/Proxmox/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 tteck
|
||||
# Author: tteck (tteckster)
|
||||
# License: MIT | https://github.com/asylumexp/Proxmox/raw/main/LICENSE
|
||||
# Source: https://github.com/rogerfar/rdt-client
|
||||
|
||||
APP="RDTClient"
|
||||
var_tags="${var_tags:-torrent}"
|
||||
var_cpu="${var_cpu:-1}"
|
||||
var_ram="${var_ram:-1024}"
|
||||
var_disk="${var_disk:-4}"
|
||||
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/rdtc/ ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
if check_for_gh_release "rdt-client" "rogerfar/rdt-client"; then
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop rdtc
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
msg_info "Creating backup"
|
||||
mkdir -p /opt/rdtc-backup
|
||||
cp -R /opt/rdtc/appsettings.json /opt/rdtc-backup/
|
||||
msg_ok "Backup created"
|
||||
|
||||
fetch_and_deploy_gh_release "rdt-client" "rogerfar/rdt-client" "prebuild" "latest" "/opt/rdtc" "RealDebridClient.zip"
|
||||
cp -R /opt/rdtc-backup/appsettings.json /opt/rdtc/
|
||||
if dpkg-query -W dotnet-sdk-8.0 >/dev/null 2>&1; then
|
||||
$STD apt remove --purge -y dotnet-sdk-8.0
|
||||
ensure_dependencies aspnetcore-runtime-9.0
|
||||
fi
|
||||
rm -rf /opt/rdtc-backup
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start rdtc
|
||||
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}:6500${CL}"
|
||||
@@ -1,119 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/asylumexp/Proxmox/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 tteck
|
||||
# Author: tteck (tteckster)
|
||||
# License: MIT | https://github.com/asylumexp/Proxmox/raw/main/LICENSE
|
||||
# Source: https://github.com/dani-garcia/vaultwarden
|
||||
|
||||
APP="Vaultwarden"
|
||||
var_tags="${var_tags:-password-manager}"
|
||||
var_cpu="${var_cpu:-4}"
|
||||
var_ram="${var_ram:-6144}"
|
||||
var_disk="${var_disk:-20}"
|
||||
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 [[ ! -f /etc/systemd/system/vaultwarden.service ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
VAULT=$(get_latest_github_release "dani-garcia/vaultwarden")
|
||||
WVRELEASE=$(get_latest_github_release "dani-garcia/bw_web_builds")
|
||||
|
||||
UPD=$(msg_menu "Vaultwarden Update Options" \
|
||||
"1" "Update VaultWarden + Web-Vault" \
|
||||
"2" "Set Admin Token")
|
||||
|
||||
if [ "$UPD" == "1" ]; then
|
||||
if check_for_gh_release "vaultwarden" "dani-garcia/vaultwarden"; then
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop vaultwarden
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
fetch_and_deploy_gh_release "vaultwarden" "dani-garcia/vaultwarden" "tarball" "latest" "/tmp/vaultwarden-src"
|
||||
|
||||
msg_info "Updating VaultWarden to $VAULT (Patience)"
|
||||
cd /tmp/vaultwarden-src
|
||||
VW_VERSION="$VAULT"
|
||||
export VW_VERSION
|
||||
$STD cargo build --features "sqlite,mysql,postgresql" --release
|
||||
if [[ -f /usr/bin/vaultwarden ]]; then
|
||||
cp target/release/vaultwarden /usr/bin/
|
||||
else
|
||||
cp target/release/vaultwarden /opt/vaultwarden/bin/
|
||||
fi
|
||||
cd ~ && rm -rf /tmp/vaultwarden-src
|
||||
msg_ok "Updated VaultWarden to ${VAULT}"
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start vaultwarden
|
||||
msg_ok "Started Service"
|
||||
else
|
||||
msg_ok "VaultWarden is already up-to-date"
|
||||
fi
|
||||
|
||||
if check_for_gh_release "vaultwarden_webvault" "dani-garcia/bw_web_builds"; then
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop vaultwarden
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
msg_info "Updating Web-Vault to $WVRELEASE"
|
||||
rm -rf /opt/vaultwarden/web-vault
|
||||
mkdir -p /opt/vaultwarden/web-vault
|
||||
|
||||
fetch_and_deploy_gh_release "vaultwarden_webvault" "dani-garcia/bw_web_builds" "prebuild" "latest" "/opt/vaultwarden/web-vault" "bw_web_*.tar.gz"
|
||||
|
||||
chown -R root:root /opt/vaultwarden/web-vault/
|
||||
msg_ok "Updated Web-Vault to ${WVRELEASE}"
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start vaultwarden
|
||||
msg_ok "Started Service"
|
||||
else
|
||||
msg_ok "Web-Vault is already up-to-date"
|
||||
fi
|
||||
|
||||
msg_ok "Updated successfully!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ "$UPD" == "2" ]; then
|
||||
if [[ "${PHS_SILENT:-0}" == "1" ]]; then
|
||||
msg_warn "Set Admin Token requires interactive mode, skipping."
|
||||
exit
|
||||
fi
|
||||
read -r -s -p "Set the ADMIN_TOKEN: " NEWTOKEN
|
||||
echo ""
|
||||
if [[ -n "$NEWTOKEN" ]]; then
|
||||
ensure_dependencies argon2
|
||||
TOKEN=$(echo -n "${NEWTOKEN}" | argon2 "$(openssl rand -base64 32)" -t 2 -m 16 -p 4 -l 64 -e)
|
||||
sed -i "s|ADMIN_TOKEN=.*|ADMIN_TOKEN='${TOKEN}'|" /opt/vaultwarden/.env
|
||||
if [[ -f /opt/vaultwarden/data/config.json ]]; then
|
||||
sed -i "s|\"admin_token\":.*|\"admin_token\": \"${TOKEN}\"|" /opt/vaultwarden/data/config.json
|
||||
fi
|
||||
systemctl restart vaultwarden
|
||||
msg_ok "Admin token updated"
|
||||
fi
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
start
|
||||
build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}https://${IP}:8000${CL}"
|
||||
@@ -1,61 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVED/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}"
|
||||
75
ct/immichframe.sh
Normal file
75
ct/immichframe.sh
Normal file
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env bash
|
||||
COMMUNITY_SCRIPTS_URL="${COMMUNITY_SCRIPTS_URL:-https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main}"
|
||||
source <(curl -fsSL "$COMMUNITY_SCRIPTS_URL/misc/build.func")
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: Thiago Canozzo Lahr (tclahr)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/immichFrame/ImmichFrame
|
||||
|
||||
APP="ImmichFrame"
|
||||
var_tags="${var_tags:-photos;slideshow}"
|
||||
var_cpu="${var_cpu:-1}"
|
||||
var_ram="${var_ram:-1024}"
|
||||
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/immichframe ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if check_for_gh_release "immichframe" "immichFrame/ImmichFrame"; then
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop immichframe
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "immichframe" "immichFrame/ImmichFrame" "tarball" "latest" "/tmp/immichframe"
|
||||
|
||||
msg_info "Building Application"
|
||||
cd /tmp/immichframe
|
||||
$STD dotnet publish ImmichFrame.WebApi/ImmichFrame.WebApi.csproj \
|
||||
--configuration Release \
|
||||
--runtime linux-x64 \
|
||||
--self-contained false \
|
||||
--output /opt/immichframe
|
||||
|
||||
cd /tmp/immichframe/immichFrame.Web
|
||||
$STD npm ci --silent
|
||||
$STD npm run build
|
||||
rm -rf /opt/immichframe/wwwroot/*
|
||||
cp -r build/* /opt/immichframe/wwwroot
|
||||
rm -rf /tmp/immichframe
|
||||
chown -R immichframe:immichframe /opt/immichframe
|
||||
msg_ok "Application Built"
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start immichframe
|
||||
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}:8080${CL}"
|
||||
echo -e "${INFO}${YW} Configuration file location:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}/opt/immichframe/Config/Settings.yml${CL}"
|
||||
echo -e "${INFO}${YW} Edit the config file and set ImmichServerUrl and ApiKey before use!${CL}"
|
||||
@@ -1,71 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: vhsdream
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||
# Source: https://github.com/iv-org/invidious
|
||||
|
||||
APP="Invidious"
|
||||
var_tags="${var_tags:-streaming}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-4}"
|
||||
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/invidious ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if check_for_gh_release "Invidious" "iv-org/invidious"; then
|
||||
msg_info "Stopping services"
|
||||
$STD systemctl stop invidious-companion invidious
|
||||
msg_ok "Stopped services"
|
||||
|
||||
msg_info "Backing up config"
|
||||
cp /opt/invidious/config/config.yml /opt/invidious-config.yml
|
||||
msg_ok "Backed up config"
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Invidious" "iv-org/invidious" "tarball" "latest" "/opt/invidious"
|
||||
if check_for_gh_release "Invidious-Companion" "iv-org/invidious-companion"; then
|
||||
CLEAN_INSTALL fetch_and_deploy_gh_release "Invidious-Companion" "iv-org/invidious-companion" "prebuild" "latest" "/opt/invidious-companion" "invidious_companion-x86_64-unknown-linux-gnu.tar.gz"
|
||||
fi
|
||||
|
||||
msg_info "Updating Invidious"
|
||||
PG_DB_PASS="$(sed -n '/Password:/s/[^:]*:[[:space:]]//p' ~/oxicloud.creds)"
|
||||
cd /opt/oxicloud
|
||||
export DATABASE_URL="postgres://oxicloud:${PG_DB_PASS}@localhost/oxicloud"
|
||||
export RUSTFLAGS="-C target-cpu=native"
|
||||
$STD cargo build --release
|
||||
mv target/release/oxicloud /usr/bin/oxicloud && chmod +x /usr/bin/oxicloud
|
||||
msg_ok "Updated Invidious"
|
||||
|
||||
msg_info "Starting Invidious"
|
||||
$STD systemctl start oxicloud
|
||||
msg_ok "Started Invidious"
|
||||
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}:8086${CL}"
|
||||
@@ -2,7 +2,7 @@
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: Matthew Stern (sternma) | MickLesk (CanbiZ)
|
||||
# Author: Matthew Stern (sternma)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||
# Source: https://github.com/dmunozv04/iSponsorBlockTV
|
||||
|
||||
@@ -35,7 +35,27 @@ function update_script() {
|
||||
systemctl stop isponsorblocktv
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "isponsorblocktv" "dmunozv04/iSponsorBlockTV" "singlefile" "latest" "/opt/isponsorblocktv" "iSponsorBlockTV-*-linux"
|
||||
if [[ -d /var/lib/isponsorblocktv ]]; then
|
||||
msg_info "Backing up Data"
|
||||
cp -r /var/lib/isponsorblocktv /var/lib/isponsorblocktv_data_backup
|
||||
msg_ok "Backed up Data"
|
||||
fi
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "isponsorblocktv" "dmunozv04/iSponsorBlockTV"
|
||||
|
||||
msg_info "Setting up iSponsorBlockTV"
|
||||
$STD python3 -m venv /opt/isponsorblocktv/venv
|
||||
$STD /opt/isponsorblocktv/venv/bin/pip install --upgrade pip
|
||||
$STD /opt/isponsorblocktv/venv/bin/pip install /opt/isponsorblocktv
|
||||
msg_ok "Set up iSponsorBlockTV"
|
||||
|
||||
if [[ -d /var/lib/isponsorblocktv_data_backup ]]; then
|
||||
msg_info "Restoring Data"
|
||||
rm -rf /var/lib/isponsorblocktv
|
||||
cp -r /var/lib/isponsorblocktv_data_backup /var/lib/isponsorblocktv
|
||||
rm -rf /var/lib/isponsorblocktv_data_backup
|
||||
msg_ok "Restored Data"
|
||||
fi
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start isponsorblocktv
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: vhsdream
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||
# Source: https://github.com/DioCrafts/OxiCloud
|
||||
|
||||
APP="OxiCloud"
|
||||
var_tags="${var_tags:-files;documents}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-3072}"
|
||||
var_disk="${var_disk:-20}"
|
||||
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/oxicloud ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if check_for_gh_release "OxiCloud" "DioCrafts/OxiCloud"; then
|
||||
msg_info "Stopping OxiCloud"
|
||||
$STD systemctl stop oxicloud
|
||||
msg_ok "Stopped OxiCloud"
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "OxiCloud" "DioCrafts/OxiCloud" "tarball" "latest" "/opt/oxicloud"
|
||||
TOOLCHAIN="$(sed -n '2s/[^:]*://p' /opt/oxicloud/Dockerfile | awk -F- '{print $1}')"
|
||||
RUST_TOOLCHAIN=$TOOLCHAIN setup_rust
|
||||
|
||||
msg_info "Updating OxiCloud"
|
||||
PG_DB_PASS="$(sed -n '/Password:/s/[^:]*:[[:space:]]//p' ~/oxicloud.creds)"
|
||||
cd /opt/oxicloud
|
||||
export DATABASE_URL="postgres://oxicloud:${PG_DB_PASS}@localhost/oxicloud"
|
||||
export RUSTFLAGS="-C target-cpu=native"
|
||||
$STD cargo build --release
|
||||
mv target/release/oxicloud /usr/bin/oxicloud && chmod +x /usr/bin/oxicloud
|
||||
msg_ok "Updated OxiCloud"
|
||||
|
||||
msg_info "Starting OxiCloud"
|
||||
$STD systemctl start oxicloud
|
||||
msg_ok "Started OxiCloud"
|
||||
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}:8086${CL}"
|
||||
@@ -1,79 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: Stephen Chin (steveonjava)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||
# Source: https://github.com/ProtonMail/proton-bridge
|
||||
|
||||
APP="ProtonMail-Bridge"
|
||||
var_tags="${var_tags:-mail;proton}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-1024}"
|
||||
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 [[ ! -x /usr/bin/protonmail-bridge ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if check_for_gh_release "protonmail-bridge" "ProtonMail/proton-bridge"; then
|
||||
local -a bridge_units=(
|
||||
protonmail-bridge
|
||||
protonmail-bridge-imap.socket
|
||||
protonmail-bridge-smtp.socket
|
||||
protonmail-bridge-imap-proxy
|
||||
protonmail-bridge-smtp-proxy
|
||||
)
|
||||
local unit
|
||||
declare -A was_active
|
||||
for unit in "${bridge_units[@]}"; do
|
||||
if systemctl is-active --quiet "$unit" 2>/dev/null; then
|
||||
was_active["$unit"]=1
|
||||
else
|
||||
was_active["$unit"]=0
|
||||
fi
|
||||
done
|
||||
|
||||
msg_info "Stopping Services"
|
||||
systemctl stop protonmail-bridge-imap.socket protonmail-bridge-smtp.socket protonmail-bridge-imap-proxy protonmail-bridge-smtp-proxy protonmail-bridge
|
||||
msg_ok "Stopped Services"
|
||||
|
||||
fetch_and_deploy_gh_release "protonmail-bridge" "ProtonMail/proton-bridge" "binary"
|
||||
|
||||
if [[ -f /home/protonbridge/.protonmailbridge-initialized ]]; then
|
||||
msg_info "Starting Services"
|
||||
for unit in "${bridge_units[@]}"; do
|
||||
if [[ "${was_active[$unit]:-0}" == "1" ]]; then
|
||||
systemctl start "$unit"
|
||||
fi
|
||||
done
|
||||
msg_ok "Started Services"
|
||||
else
|
||||
msg_ok "Initialization not completed. Services remain disabled."
|
||||
fi
|
||||
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}One-time configuration is required before Bridge services are enabled.${CL}"
|
||||
echo -e "${INFO}${YW}Run this command in the container: protonmailbridge-configure${CL}"
|
||||
@@ -65,5 +65,3 @@ 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}"
|
||||
echo -e "${INFO}${YW} Before first use, configure auth in:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}/opt/split-pro/.env${CL}"
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||
# Source: https://github.com/versity/versitygw
|
||||
|
||||
APP="VersityGW"
|
||||
var_tags="${var_tags:-s3;storage;gateway}"
|
||||
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 [[ ! -f /usr/bin/versitygw ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if check_for_gh_release "versitygw" "versity/versitygw"; then
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop versitygw@gateway
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
fetch_and_deploy_gh_release "versitygw" "versity/versitygw" "binary"
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start versitygw@gateway
|
||||
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}:7070${CL}"
|
||||
83
ct/yamtrack.sh
Normal file
83
ct/yamtrack.sh
Normal file
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVED/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}"
|
||||
@@ -705,7 +705,7 @@ cleanup_lxc
|
||||
- [ ] `motd_ssh`, `customize`, `cleanup_lxc` at the end
|
||||
- [ ] No custom download/version-check logic
|
||||
- [ ] No default `(Patience)` text in msg_info labels
|
||||
- [ ] JSON metadata file created in `json/<appname>.json`
|
||||
- [ ] JSON metadata file created in `frontend/public/json/<appname>.json`
|
||||
|
||||
---
|
||||
|
||||
@@ -727,7 +727,7 @@ cleanup_lxc
|
||||
|
||||
## <20> JSON Metadata Files
|
||||
|
||||
Every application requires a JSON metadata file in `json/<appname>.json`.
|
||||
Every application requires a JSON metadata file in `frontend/public/json/<appname>.json`.
|
||||
|
||||
### JSON Structure
|
||||
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
# App Deployer VM
|
||||
|
||||
Deploy LXC applications inside a full Virtual Machine instead of an LXC container.
|
||||
|
||||
## Overview
|
||||
|
||||
The App Deployer VM bridges the gap between CT install scripts (`install/*.sh`) and VM infrastructure. It leverages the existing install scripts — originally designed for LXC containers — and runs them **live during image build** via `virt-customize --run`.
|
||||
|
||||
### Supported Operating Systems
|
||||
|
||||
| OS | Version | Codename | Cloud-Init |
|
||||
| ------ | --------- | -------- | ---------- |
|
||||
| Debian | 13 | Trixie | Optional |
|
||||
| Debian | 12 | Bookworm | Optional |
|
||||
| Ubuntu | 24.04 LTS | Noble | Required |
|
||||
| Ubuntu | 22.04 LTS | Jammy | Required |
|
||||
|
||||
## Usage
|
||||
|
||||
### Create a new App VM (interactive)
|
||||
|
||||
```bash
|
||||
bash -c "$(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/vm/app-deployer-vm.sh)"
|
||||
```
|
||||
|
||||
### Pre-select application
|
||||
|
||||
```bash
|
||||
APP_SELECT=yamtrack bash -c "$(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/vm/app-deployer-vm.sh)"
|
||||
```
|
||||
|
||||
### Update the application later (inside the VM)
|
||||
|
||||
```bash
|
||||
bash -c "$(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/ct/<app>.sh)"
|
||||
```
|
||||
|
||||
For example, to update Yamtrack:
|
||||
|
||||
```bash
|
||||
bash -c "$(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/ct/yamtrack.sh)"
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
### Installation Flow
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ Proxmox Host │
|
||||
│ │
|
||||
│ 1. Select app (e.g. Yamtrack) │
|
||||
│ 2. Select OS (e.g. Debian 13) │
|
||||
│ 3. Configure VM resources │
|
||||
│ 4. Download cloud image │
|
||||
│ 5. virt-customize: │
|
||||
│ - Install base packages │
|
||||
│ - Inject install.func │
|
||||
│ - Inject tools.func │
|
||||
│ - Run install script LIVE │
|
||||
│ (virt-customize --run) │
|
||||
│ - Configure hostname & SSH │
|
||||
│ 6. Create VM (qm create) │
|
||||
│ 7. Import customized disk │
|
||||
│ 8. Start VM │
|
||||
│ │
|
||||
│ → Application pre-installed! │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Update Flow
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ Inside the VM (SSH or console) │
|
||||
│ │
|
||||
│ bash -c "$(curl -fsSL │
|
||||
│ $COMMUNITY_SCRIPTS_URL/ │
|
||||
│ ct/<app>.sh)" │
|
||||
│ │
|
||||
│ → start() detects no pveversion │
|
||||
│ → Shows update/settings menu │
|
||||
│ → Runs update_script() │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
The update mechanism reuses the existing CT script logic. Since `pveversion` is not available inside the VM, the `start()` function automatically enters the update/settings mode — exactly the same as running updates in LXC containers.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Files
|
||||
|
||||
| File | Purpose |
|
||||
| ----------------------- | ------------------------------------------- |
|
||||
| `vm/app-deployer-vm.sh` | Main user-facing script |
|
||||
| `misc/vm-app.func` | Core library for VM app deployment |
|
||||
| `misc/vm-core.func` | Shared VM functions (colors, spinner, etc.) |
|
||||
| `misc/cloud-init.func` | Cloud-Init configuration (optional) |
|
||||
|
||||
### Key Design Decisions
|
||||
|
||||
1. **Install scripts run unmodified** — The same `install/*.sh` scripts that work in LXC containers work inside VMs. The environment (`FUNCTIONS_FILE_PATH`, exports) is replicated identically.
|
||||
|
||||
2. **Image customization via `virt-customize`** — All dependencies are installed and the app install script runs live inside the qcow2 image during build. No SSH or guest agent required during setup.
|
||||
|
||||
3. **Live installation** — The install script runs during image build (not on first boot), so the application is ready immediately when the VM starts.
|
||||
|
||||
4. **Update via CT script URL** — Run the same `bash -c "$(curl ...ct/<app>.sh)"` command inside the VM, just like in an LXC container.
|
||||
|
||||
### Environment Variables (set during image build)
|
||||
|
||||
| Variable | Description |
|
||||
| ----------------------- | ---------------------------------- |
|
||||
| `FUNCTIONS_FILE_PATH` | Full contents of `install.func` |
|
||||
| `APPLICATION` | App display name (e.g. "Yamtrack") |
|
||||
| `app` | App identifier (e.g. "yamtrack") |
|
||||
| `VERBOSE` | "no" (silent mode) |
|
||||
| `SSH_ROOT` | "yes" |
|
||||
| `PCT_OSTYPE` | OS type (debian/ubuntu) |
|
||||
| `PCT_OSVERSION` | OS version (12/13/22.04/24.04) |
|
||||
| `COMMUNITY_SCRIPTS_URL` | Repository base URL |
|
||||
| `DEPLOY_TARGET` | "vm" (distinguishes from LXC) |
|
||||
|
||||
### VM Directory Structure
|
||||
|
||||
```
|
||||
/opt/community-scripts/
|
||||
├── install.func # Function library
|
||||
└── tools.func # Helper functions
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
- **Alpine-based apps**: Currently only Debian/Ubuntu VMs are supported. Alpine install scripts are not compatible.
|
||||
- **LXC-specific features**: Some CT features (FUSE, TUN, GPU passthrough) are configured differently in VMs.
|
||||
- **`cleanup_lxc`**: This function works fine in VMs (it only cleans package caches), but the name is LXC-centric.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Check build log
|
||||
|
||||
If the installation fails during image build, check the log on the Proxmox host:
|
||||
|
||||
```bash
|
||||
cat /tmp/vm-app-install.log
|
||||
```
|
||||
|
||||
### Re-run installation
|
||||
|
||||
Re-build the VM from scratch — since the app is installed during image build, there is no in-VM reinstall mechanism. Simply delete the VM and run the deployer again.
|
||||
|
||||
### Verify installation worked
|
||||
|
||||
After the VM boots, SSH in and check if the application service is running:
|
||||
|
||||
```bash
|
||||
systemctl status <app-service-name>
|
||||
```
|
||||
5
frontend/.eslintrc.json
generated
Normal file
5
frontend/.eslintrc.json
generated
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": ["next/core-web-vitals"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["@typescript-eslint"]
|
||||
}
|
||||
39
frontend/.gitignore
vendored
Normal file
39
frontend/.gitignore
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
.yarn/install-state.gz
|
||||
|
||||
# wrangler
|
||||
.worker-next
|
||||
.wrangler
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
out
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# # local env files
|
||||
# .env*.local
|
||||
# .env
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
5
frontend/.prettierignore
Normal file
5
frontend/.prettierignore
Normal file
@@ -0,0 +1,5 @@
|
||||
dist
|
||||
node_modules
|
||||
.next
|
||||
build
|
||||
.contentlayer
|
||||
3
frontend/.prettierrc
Normal file
3
frontend/.prettierrc
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["prettier-plugin-tailwindcss", "prettier-plugin-organize-imports"]
|
||||
}
|
||||
21
frontend/LICENSE
Normal file
21
frontend/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Bram Suurd
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
17
frontend/components.json
generated
Normal file
17
frontend/components.json
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "default",
|
||||
"rsc": true,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.ts",
|
||||
"css": "@/styles/globals.css",
|
||||
"baseColor": "slate",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils"
|
||||
}
|
||||
}
|
||||
25
frontend/next.config.mjs
Normal file
25
frontend/next.config.mjs
Normal file
@@ -0,0 +1,25 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
webpack: (config) => {
|
||||
config.resolve.alias.canvas = false;
|
||||
|
||||
return config;
|
||||
},
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
protocol: "https",
|
||||
hostname: "**",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
env: {
|
||||
BASE_PATH: "ProxmoxVED",
|
||||
},
|
||||
|
||||
output: "export",
|
||||
basePath: `/ProxmoxVED`,
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
10816
frontend/package-lock.json
generated
Normal file
10816
frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
93
frontend/package.json
generated
Normal file
93
frontend/package.json
generated
Normal file
@@ -0,0 +1,93 @@
|
||||
{
|
||||
"name": "proxmox-helper-scripts-website",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"author": {
|
||||
"name": "Bram Suurd",
|
||||
"url": "https://github.com/community-scripts"
|
||||
},
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "next dev --turbopack",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"test": "vitest",
|
||||
"deploy": "next build && touch out/.nojekyll && git add out/ && git commit -m \"Deploy\" && git subtree push --prefix out origin gh-pages",
|
||||
"format:write": "prettier --write \"**/*.{ts,tsx,mdx}\" --cache",
|
||||
"format:check": "prettier --check \"**/*.{ts,tsx,mdx}\" --cache",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-accordion": "^1.2.3",
|
||||
"@radix-ui/react-dialog": "^1.1.6",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
||||
"@radix-ui/react-icons": "^1.3.2",
|
||||
"@radix-ui/react-label": "^2.1.2",
|
||||
"@radix-ui/react-navigation-menu": "^1.2.5",
|
||||
"@radix-ui/react-popover": "^1.1.6",
|
||||
"@radix-ui/react-select": "^2.1.6",
|
||||
"@radix-ui/react-separator": "^1.1.2",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
"@radix-ui/react-switch": "^1.1.3",
|
||||
"@radix-ui/react-tabs": "^1.1.3",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"@tanstack/react-query": "^5.71.1",
|
||||
"chart.js": "^4.4.8",
|
||||
"chartjs-plugin-datalabels": "^2.2.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"framer-motion": "^11.18.2",
|
||||
"fuse.js": "^7.1.0",
|
||||
"lucide-react": "^0.453.0",
|
||||
"mini-svg-data-uri": "^1.4.4",
|
||||
"next": "15.5.7",
|
||||
"next-themes": "^0.3.0",
|
||||
"nuqs": "^2.4.1",
|
||||
"pocketbase": "^0.21.5",
|
||||
"prettier-plugin-organize-imports": "^4.1.0",
|
||||
"react": "19.0.0",
|
||||
"react-chartjs-2": "^5.3.0",
|
||||
"react-code-blocks": "^0.1.6",
|
||||
"react-datepicker": "^7.6.0",
|
||||
"react-day-picker": "8.10.1",
|
||||
"react-dom": "19.0.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-simple-typewriter": "^5.0.1",
|
||||
"sharp": "^0.33.5",
|
||||
"simple-icons": "^13.21.0",
|
||||
"sonner": "^1.7.4",
|
||||
"tailwind-merge": "^2.6.0",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tanstack/eslint-plugin-query": "^5.68.0",
|
||||
"@testing-library/dom": "^10.4.0",
|
||||
"@testing-library/react": "^16.2.0",
|
||||
"@types/node": "^22.13.16",
|
||||
"@types/react": "npm:types-react@19.0.0-rc.1",
|
||||
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.29.0",
|
||||
"@typescript-eslint/parser": "^8.29.0",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"eslint": "^9.23.0",
|
||||
"eslint-config-next": "15.0.2",
|
||||
"jsdom": "^25.0.1",
|
||||
"postcss": "^8.5.3",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"tailwindcss-animated": "^1.1.2",
|
||||
"typescript": "^5.8.2",
|
||||
"vite-tsconfig-paths": "^5.1.4",
|
||||
"vitest": "^3.1.1"
|
||||
},
|
||||
"overrides": {
|
||||
"@types/react": "npm:types-react@19.0.0-rc.1",
|
||||
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.1"
|
||||
}
|
||||
}
|
||||
8
frontend/postcss.config.mjs
Normal file
8
frontend/postcss.config.mjs
Normal file
@@ -0,0 +1,8 @@
|
||||
/** @type {import('postcss-load-config').Config} */
|
||||
const config = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
BIN
frontend/public/defaultimg.png
Normal file
BIN
frontend/public/defaultimg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
40
frontend/public/json/immichframe.json
Normal file
40
frontend/public/json/immichframe.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "ImmichFrame",
|
||||
"slug": "immichframe",
|
||||
"categories": [
|
||||
13
|
||||
],
|
||||
"date_created": "2026-02-26",
|
||||
"type": "ct",
|
||||
"updateable": true,
|
||||
"privileged": false,
|
||||
"interface_port": 8080,
|
||||
"documentation": null,
|
||||
"config_path": "/opt/immichframe/Config/Settings.yml",
|
||||
"website": null,
|
||||
"logo": "https://github.com/selfhst/icons/blob/main/webp/immich-frame.webp",
|
||||
"description": "ImmichFrame is a digital photo frame web application that connects to your Immich server and displays your photos as a fullscreen slideshow.",
|
||||
"install_methods": [
|
||||
{
|
||||
"type": "default",
|
||||
"script": "ct/immichframe.sh",
|
||||
"resources": {
|
||||
"cpu": 1,
|
||||
"ram": 1024,
|
||||
"hdd": 8,
|
||||
"os": "Debian",
|
||||
"version": "13"
|
||||
}
|
||||
}
|
||||
],
|
||||
"default_credentials": {
|
||||
"username": null,
|
||||
"password": null
|
||||
},
|
||||
"notes": [
|
||||
{
|
||||
"text": "After installation, edit `/opt/immichframe/Config/Settings.yml` and set ImmichServerUrl and ApiKey. Then restart the service with `systemctl restart immichframe`.",
|
||||
"type": "info"
|
||||
}
|
||||
]
|
||||
}
|
||||
44
frontend/public/json/yamtrack.json
Normal file
44
frontend/public/json/yamtrack.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "Yamtrack",
|
||||
"slug": "yamtrack",
|
||||
"categories": [
|
||||
13
|
||||
],
|
||||
"date_created": "2026-02-22",
|
||||
"type": "ct",
|
||||
"updateable": true,
|
||||
"privileged": false,
|
||||
"interface_port": 8000,
|
||||
"documentation": "https://github.com/FuzzyGrim/Yamtrack/wiki",
|
||||
"website": "https://github.com/FuzzyGrim/Yamtrack",
|
||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/yamtrack.webp",
|
||||
"config_path": "/opt/yamtrack/src/.env",
|
||||
"description": "Yamtrack is a self-hosted media tracker for movies, TV shows, anime, manga, video games, books, comics, and board games with multi-user support and Celery-powered background tasks.",
|
||||
"install_methods": [
|
||||
{
|
||||
"type": "default",
|
||||
"script": "ct/yamtrack.sh",
|
||||
"resources": {
|
||||
"cpu": 2,
|
||||
"ram": 2048,
|
||||
"hdd": 8,
|
||||
"os": "Debian",
|
||||
"version": "13"
|
||||
}
|
||||
}
|
||||
],
|
||||
"default_credentials": {
|
||||
"username": null,
|
||||
"password": null
|
||||
},
|
||||
"notes": [
|
||||
{
|
||||
"text": "Set API keys (TMDB_API, MAL_API, IGDB_ID, IGDB_SECRET) in /opt/yamtrack/src/.env to enable media search from external providers.",
|
||||
"type": "info"
|
||||
},
|
||||
{
|
||||
"text": "If using a reverse proxy, set the URLS variable in .env to your external URL (e.g., URLS=https://yamtrack.example.com).",
|
||||
"type": "warning"
|
||||
}
|
||||
]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user