diff --git a/.github/workflows/update-versions-github.yml b/.github/workflows/update-versions-github.yml new file mode 100644 index 000000000..5c18ef2e5 --- /dev/null +++ b/.github/workflows/update-versions-github.yml @@ -0,0 +1,512 @@ +name: Update Versions from GitHub + +on: + workflow_dispatch: + schedule: + # Runs at 06:00 and 18:00 UTC + - cron: "0 6,18 * * *" + +permissions: + contents: write + pull-requests: write + +env: + SOURCES_FILE: frontend/public/json/version-sources.json + VERSIONS_FILE: frontend/public/json/versions.json + +jobs: + update-versions: + if: github.repository == 'community-scripts/ProxmoxVE' + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + ref: main + + - name: Generate GitHub App Token + id: generate-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ vars.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + + - name: Extract version sources from install scripts + run: | + set -euo pipefail + + echo "=========================================" + echo " Extracting version sources from scripts" + echo "=========================================" + + # Initialize sources array + sources_json="[]" + + # Function to add a source entry + add_source() { + local slug="$1" + local type="$2" + local source="$3" + local script="$4" + + # Check if slug already exists (avoid duplicates) + if echo "$sources_json" | jq -e ".[] | select(.slug == \"$slug\")" > /dev/null 2>&1; then + return + fi + + sources_json=$(echo "$sources_json" | jq \ + --arg slug "$slug" \ + --arg type "$type" \ + --arg source "$source" \ + --arg script "$script" \ + '. += [{"slug": $slug, "type": $type, "source": $source, "script": $script, "version": null, "date": null}]') + } + + echo "" + echo "=== Method 1: fetch_and_deploy_gh_release calls ===" + count=0 + for script in install/*-install.sh; do + [[ ! -f "$script" ]] && continue + slug=$(basename "$script" | sed 's/-install\.sh$//') + + # Extract repo from fetch_and_deploy_gh_release "app" "owner/repo" + while IFS= read -r line; do + if [[ "$line" =~ fetch_and_deploy_gh_release[[:space:]]+\"[^\"]*\"[[:space:]]+\"([^\"]+)\" ]]; then + repo="${BASH_REMATCH[1]}" + add_source "$slug" "github" "$repo" "$script" + ((count++)) + break # Only first match per script + fi + done < <(grep 'fetch_and_deploy_gh_release' "$script" 2>/dev/null || true) + done + echo "Found $count scripts with fetch_and_deploy_gh_release" + + echo "" + echo "=== Method 2: GitHub URLs in scripts (fallback) ===" + count=0 + for script in install/*-install.sh; do + [[ ! -f "$script" ]] && continue + slug=$(basename "$script" | sed 's/-install\.sh$//') + + # Skip if already found + if echo "$sources_json" | jq -e ".[] | select(.slug == \"$slug\")" > /dev/null 2>&1; then + continue + fi + + # Look for github.com/owner/repo patterns + repo=$(grep -oE 'github\.com/([a-zA-Z0-9_-]+/[a-zA-Z0-9_.-]+)' "$script" 2>/dev/null \ + | sed 's|github\.com/||' \ + | sed 's/\.git$//' \ + | grep -v 'community-scripts/ProxmoxVE' \ + | grep -v '^repos/' \ + | head -1 || true) + + if [[ -n "$repo" && "$repo" =~ ^[a-zA-Z0-9_-]+/[a-zA-Z0-9_.-]+$ ]]; then + add_source "$slug" "github" "$repo" "$script" + ((count++)) + fi + done + echo "Found $count additional scripts with GitHub URLs" + + echo "" + echo "=== Method 3: npm packages ===" + # Detect npm install --global + for script in install/*-install.sh; do + [[ ! -f "$script" ]] && continue + slug=$(basename "$script" | sed 's/-install\.sh$//') + + # Skip if already found + if echo "$sources_json" | jq -e ".[] | select(.slug == \"$slug\")" > /dev/null 2>&1; then + continue + fi + + # Look for npm install --global + pkg=$(grep -oE 'npm install[^|;]*--global[^|;]*' "$script" 2>/dev/null \ + | grep -oE '\s[a-z][a-z0-9_-]+(@[^\s]+)?$' \ + | tr -d ' ' \ + | sed 's/@.*//' \ + | tail -1 || true) + + if [[ -n "$pkg" ]]; then + add_source "$slug" "npm" "$pkg" "$script" + fi + done + + echo "" + echo "=== Method 4: Docker images ===" + # Known Docker-based apps (from docker pull or docker run) + declare -A docker_mappings=( + ["homeassistant"]="homeassistant/home-assistant" + ["portainer"]="portainer/portainer-ce" + ["dockge"]="louislam/dockge" + ["immich"]="ghcr.io/immich-app/immich-server" + ["audiobookshelf"]="ghcr.io/advplyr/audiobookshelf" + ["podman-homeassistant"]="homeassistant/home-assistant" + ) + + for slug in "${!docker_mappings[@]}"; do + image="${docker_mappings[$slug]}" + if ! echo "$sources_json" | jq -e ".[] | select(.slug == \"$slug\")" > /dev/null 2>&1; then + add_source "$slug" "docker" "$image" "install/${slug}-install.sh" + fi + done + + echo "" + echo "=== Method 5: Manual GitHub mappings (apt-based apps) ===" + # Apps that install via apt but have GitHub releases for version tracking + declare -A manual_github_mappings=( + ["actualbudget"]="actualbudget/actual" + ["apache-cassandra"]="apache/cassandra" + ["apache-couchdb"]="apache/couchdb" + ["apache-guacamole"]="apache/guacamole-server" + ["apache-tomcat"]="apache/tomcat" + ["archivebox"]="ArchiveBox/ArchiveBox" + ["aria2"]="aria2/aria2" + ["asterisk"]="asterisk/asterisk" + ["casaos"]="IceWhaleTech/CasaOS" + ["checkmk"]="Checkmk/checkmk" + ["cloudflared"]="cloudflare/cloudflared" + ["coolify"]="coollabsio/coolify" + ["crafty-controller"]="crafty-controller/crafty-4" + ["cross-seed"]="cross-seed/cross-seed" + ["deconz"]="dresden-elektronik/deconz-rest-plugin" + ["deluge"]="deluge-torrent/deluge" + ["dokploy"]="Dokploy/dokploy" + ["emqx"]="emqx/emqx" + ["esphome"]="esphome/esphome" + ["flowiseai"]="FlowiseAI/Flowise" + ["forgejo"]="forgejo/forgejo" + ["garage"]="deuxfleurs-org/garage" + ["ghost"]="TryGhost/Ghost" + ["grafana"]="grafana/grafana" + ["graylog"]="Graylog2/graylog2-server" + ["homebridge"]="homebridge/homebridge" + ["hyperhdr"]="awawa-dev/HyperHDR" + ["hyperion"]="hyperion-project/hyperion.ng" + ["influxdb"]="influxdata/influxdb" + ["iobroker"]="ioBroker/ioBroker" + ["jenkins"]="jenkinsci/jenkins" + ["komodo"]="moghingold/komodo" + ["lazylibrarian"]="lazylibrarian/LazyLibrarian" + ["limesurvey"]="LimeSurvey/LimeSurvey" + ["mariadb"]="MariaDB/server" + ["mattermost"]="mattermost/mattermost" + ["meshcentral"]="Ylianst/MeshCentral" + ["metabase"]="metabase/metabase" + ["mongodb"]="mongodb/mongo" + ["mysql"]="mysql/mysql-server" + ["neo4j"]="neo4j/neo4j" + ["node-red"]="node-red/node-red" + ["ntfy"]="binwiederhier/ntfy" + ["nzbget"]="nzbgetcom/nzbget" + ["octoprint"]="OctoPrint/OctoPrint" + ["onedev"]="theonedev/onedev" + ["onlyoffice"]="ONLYOFFICE/DocumentServer" + ["openhab"]="openhab/openhab-distro" + ["openobserve"]="openobserve/openobserve" + ["openwebui"]="open-webui/open-webui" + ["passbolt"]="passbolt/passbolt_api" + ["pihole"]="pi-hole/pi-hole" + ["postgresql"]="postgres/postgres" + ["rabbitmq"]="rabbitmq/rabbitmq-server" + ["readarr"]="Readarr/Readarr" + ["redis"]="redis/redis" + ["runtipi"]="runtipi/runtipi" + ["sftpgo"]="drakkan/sftpgo" + ["shinobi"]="ShinobiCCTV/Shinobi" + ["sonarqube"]="SonarSource/sonarqube" + ["sonarr"]="Sonarr/Sonarr" + ["syncthing"]="syncthing/syncthing" + ["tdarr"]="HaveAGitGat/Tdarr" + ["technitiumdns"]="TechnitiumSoftware/DnsServer" + ["transmission"]="transmission/transmission" + ["typesense"]="typesense/typesense" + ["unmanic"]="Unmanic/unmanic" + ["valkey"]="valkey-io/valkey" + ["verdaccio"]="verdaccio/verdaccio" + ["vikunja"]="go-vikunja/vikunja" + ["wazuh"]="wazuh/wazuh" + ["wordpress"]="WordPress/WordPress" + ["zabbix"]="zabbix/zabbix" + ["zammad"]="zammad/zammad" + ["zerotier-one"]="zerotier/ZeroTierOne" + # Apps without known GitHub repos (use "-" as placeholder) + ["agentdvr"]="-" + ["apt-cacher-ng"]="-" + ["channels"]="-" + ["daemonsync"]="-" + ["dotnetaspwebapi"]="-" + ["fhem"]="-" + ["fileflows"]="-" + ["fumadocs"]="-" + ["infisical"]="-" + ["itsm-ng"]="-" + ["jupyternotebook"]="-" + ["kasm"]="-" + ["lyrionmusicserver"]="-" + ["minarca"]="-" + ["mqtt"]="-" + ["nextcloudpi"]="-" + ["nextpvr"]="-" + ["notifiarr"]="-" + ["nxwitness"]="-" + ["omada"]="-" + ["omv"]="-" + ["plex"]="-" + ["podman"]="-" + ["readeck"]="-" + ["resiliosync"]="-" + ["smokeping"]="-" + ["splunk-enterprise"]="-" + ["sqlserver2022"]="-" + ["swizzin"]="-" + ["teamspeak-server"]="-" + ["twingate-connector"]="-" + ["unifi"]="-" + ["urbackupserver"]="-" + ["yunohost"]="-" + ) + + for slug in "${!manual_github_mappings[@]}"; do + repo="${manual_github_mappings[$slug]}" + if ! echo "$sources_json" | jq -e ".[] | select(.slug == \"$slug\")" > /dev/null 2>&1; then + # Skip placeholder entries in extraction, they get added in Method 8 + [[ "$repo" == "-" ]] && continue + add_source "$slug" "github" "$repo" "install/${slug}-install.sh" + fi + done + + echo "" + echo "=== Method 6: Proxmox LXC templates ===" + # Base OS versions from Proxmox template index + declare -A pveam_mappings=( + ["debian"]="pveam:debian" + ["ubuntu"]="pveam:ubuntu" + ["alpine"]="pveam:alpine" + ) + + for slug in "${!pveam_mappings[@]}"; do + template="${pveam_mappings[$slug]}" + if ! echo "$sources_json" | jq -e ".[] | select(.slug == \"$slug\")" > /dev/null 2>&1; then + add_source "$slug" "pveam" "$template" "ct/${slug}.sh" + fi + done + + echo "" + echo "=== Method 7: Special sources ===" + # Home Assistant OS VM + if ! echo "$sources_json" | jq -e ".[] | select(.slug == \"haos-vm\")" > /dev/null 2>&1; then + add_source "haos-vm" "github" "home-assistant/operating-system" "vm/haos-vm.sh" + fi + + echo "" + echo "=== Method 8: Unknown/Manual apps ===" + # Apps without known version sources - add with type "manual" for manual updates + unknown_apps=( + "agentdvr" "apt-cacher-ng" "channels" "daemonsync" "dotnetaspwebapi" + "fhem" "fileflows" "fumadocs" "infisical" "itsm-ng" "jupyternotebook" + "kasm" "lyrionmusicserver" "minarca" "mqtt" "nextcloudpi" "nextpvr" + "notifiarr" "nxwitness" "omada" "omv" "plex" "podman" "readeck" + "resiliosync" "smokeping" "splunk-enterprise" "sqlserver2022" "swizzin" + "teamspeak-server" "twingate-connector" "unifi" "urbackupserver" "yunohost" + ) + + for slug in "${unknown_apps[@]}"; do + if ! echo "$sources_json" | jq -e ".[] | select(.slug == \"$slug\")" > /dev/null 2>&1; then + add_source "$slug" "manual" "-" "install/${slug}-install.sh" + fi + done + + # Save sources file + echo "$sources_json" | jq --arg date "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ + '{generated: $date, sources: (. | sort_by(.slug))}' > "$SOURCES_FILE" + + total=$(echo "$sources_json" | jq 'length') + echo "" + echo "=========================================" + echo " Total sources extracted: $total" + echo "=========================================" + + - name: Fetch versions for all sources + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + run: | + set -euo pipefail + + echo "=========================================" + echo " Fetching versions from sources" + echo "=========================================" + + success=0 + failed=0 + manual=0 + total=$(jq '.sources | length' "$SOURCES_FILE") + + # Process each source + for i in $(seq 0 $((total - 1))); do + entry=$(jq -r ".sources[$i]" "$SOURCES_FILE") + slug=$(echo "$entry" | jq -r '.slug') + type=$(echo "$entry" | jq -r '.type') + source=$(echo "$entry" | jq -r '.source') + + echo -n "[$((i+1))/$total] $slug ($type: $source) ... " + + version="" + date="" + + case "$type" in + github) + # Try releases first + response=$(gh api "repos/${source}/releases/latest" 2>/dev/null || echo '{"message": "Not Found"}') + + 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') + else + # Fallback to tags + version=$(gh api "repos/${source}/tags" --jq '.[0].name // empty' 2>/dev/null || echo "") + fi + ;; + + npm) + response=$(curl -fsSL "https://registry.npmjs.org/${source}/latest" 2>/dev/null || echo '{}') + version=$(echo "$response" | jq -r '.version // empty') + ;; + + docker) + if [[ "$source" == ghcr.io/* ]]; then + # GitHub Container Registry + ghcr_path="${source#ghcr.io/}" + owner="${ghcr_path%%/*}" + pkg="${ghcr_path##*/}" + version=$(gh api "users/${owner}/packages/container/${pkg}/versions" --jq '.[0].metadata.container.tags[] | select(. != "latest")' 2>/dev/null | head -1 || echo "") + else + # Docker Hub + version=$(curl -fsSL "https://hub.docker.com/v2/repositories/${source}/tags?page_size=10&ordering=last_updated" 2>/dev/null \ + | jq -r '.results[] | select(.name != "latest") | .name' | head -1 || echo "") + fi + ;; + + pveam) + # Proxmox LXC template versions from download.proxmox.com + os_name="${source#pveam:}" + # Fetch the template index and get latest version + version=$(curl -fsSL "http://download.proxmox.com/images/system/" 2>/dev/null \ + | grep -oE "${os_name}-[0-9]+\.[0-9]+-default_[0-9]+_amd64" \ + | sed "s/${os_name}-//" | sed 's/-default.*//' \ + | sort -V | tail -1 || echo "") + ;; + + manual) + # Manual entries - no automatic version fetching + # These need to be updated manually or have their source type changed + version="-" + ((manual++)) + echo -n "(manual) " + ;; + esac + + if [[ -n "$version" && "$version" != "null" ]]; then + # Update the source entry with version + jq --arg idx "$i" --arg version "$version" --arg date "${date:-}" \ + '.sources[$idx | tonumber].version = $version | .sources[$idx | tonumber].date = $date' \ + "$SOURCES_FILE" > "${SOURCES_FILE}.tmp" && mv "${SOURCES_FILE}.tmp" "$SOURCES_FILE" + echo "✓ $version" + ((success++)) + else + echo "⚠ no version found" + ((failed++)) + fi + done + + echo "" + echo "=========================================" + echo " SUMMARY" + echo "=========================================" + echo "Success: $success (automated)" + echo "Manual: $manual (placeholder)" + echo "Failed: $failed" + echo "Total: $total" + echo "=========================================" + + - name: Generate versions.json for compatibility + run: | + # Convert version-sources.json to versions.json format for backward compatibility + jq '[.sources[] | select(.version != null) | {name: .source, version: .version, date: .date}]' \ + "$SOURCES_FILE" > "$VERSIONS_FILE" + + echo "Generated versions.json with $(jq length "$VERSIONS_FILE") entries" + + - name: Check for changes + id: check-changes + run: | + if git diff --quiet "$SOURCES_FILE" "$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 "$SOURCES_FILE" "$VERSIONS_FILE" 2>/dev/null || true + fi + + - name: Create Pull Request + if: steps.check-changes.outputs.changed == 'true' + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + run: | + BRANCH_NAME="automated/update-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 "$SOURCES_FILE" "$VERSIONS_FILE" + git commit -m "chore: update version-sources.json and versions.json + + Sources: $(jq '.sources | length' "$SOURCES_FILE") + With versions: $(jq '[.sources[] | select(.version != null)] | length' "$SOURCES_FILE") + Generated: $(jq -r '.generated' "$SOURCES_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 version-sources.json" \ + --body "This PR updates version information from multiple sources. + + ## Sources + - **GitHub Releases**: Direct from \`fetch_and_deploy_gh_release\` calls + - **GitHub URLs**: Extracted from install scripts + - **npm Registry**: For Node.js based apps + - **Docker Hub/GHCR**: For container-based apps + + ## Stats + - Total sources: $(jq '.sources | length' "$SOURCES_FILE") + - With versions: $(jq '[.sources[] | select(.version != null)] | length' "$SOURCES_FILE") + + --- + *Automatically generated from install scripts*" \ + --base main \ + --head "$BRANCH_NAME" \ + --label "automated pr" + fi + + - name: Auto-approve PR + if: steps.check-changes.outputs.changed == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + BRANCH_NAME="automated/update-versions-$(date +%Y%m%d)" + pr_number=$(gh pr list --head "$BRANCH_NAME" --state open --json number --jq '.[0].number') + if [[ -n "$pr_number" ]]; then + gh pr review "$pr_number" --approve + fi diff --git a/ct/flatnotes.sh b/ct/flatnotes.sh new file mode 100644 index 000000000..8fd2aa101 --- /dev/null +++ b/ct/flatnotes.sh @@ -0,0 +1,79 @@ +#!/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: luismco +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Source: https://github.com/dullage/flatnotes + +APP="Flatnotes" +var_tags="${var_tags:-notes}" +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/flatnotes ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if check_for_gh_release "flatnotes" "dullage/flatnotes"; then + msg_info "Stopping Service" + systemctl stop flatnotes + msg_ok "Stopped Service" + + msg_info "Backing up Configuration and Data" + cp /opt/flatnotes/.env /opt/flatnotes.env + cp -r /opt/flatnotes/data /opt/flatnotes_data_backup + msg_ok "Backed up Configuration and Data" + + fetch_and_deploy_gh_release "flatnotes" "dullage/flatnotes" + + msg_info "Updating Frontend" + cd /opt/flatnotes/client + $STD npm install + $STD npm run build + msg_ok "Updated Frontend" + + msg_info "Updating Backend" + cd /opt/flatnotes + rm -f uv.lock + $STD /usr/local/bin/uvx migrate-to-uv + $STD /usr/local/bin/uv sync + msg_ok "Updated Backend" + + msg_info "Restoring Configuration and Data" + cp /opt/flatnotes.env /opt/flatnotes/.env + cp -r /opt/flatnotes_data_backup/. /opt/flatnotes/data + rm -f /opt/flatnotes.env + rm -r /opt/flatnotes_data_backup + msg_ok "Restored Configuration and Data" + + msg_info "Starting Service" + systemctl start flatnotes + 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}" + diff --git a/ct/headers/qui b/ct/headers/qui deleted file mode 100644 index 1f3048cf7..000000000 --- a/ct/headers/qui +++ /dev/null @@ -1,6 +0,0 @@ - ____ _ - / __ \__ __(_) - / / / / / / / / -/ /_/ / /_/ / / -\___\_\__,_/_/ - diff --git a/ct/nextexplorer.sh b/ct/nextexplorer.sh index 6b2b651b4..27fcf564f 100644 --- a/ct/nextexplorer.sh +++ b/ct/nextexplorer.sh @@ -54,6 +54,7 @@ function update_script() { mv backend/{node_modules,src,package.json} "$APP_DIR" mv frontend/dist/ "$APP_DIR"/src/public chown -R explorer:explorer "$APP_DIR" /etc/nextExplorer + sed -i "\|version|s|$(jq -cr '.version' ${APP_DIR}/package.json)|$(cat ~/.nextexplorer)|" "$APP_DIR"/package.json msg_ok "Updated nextExplorer" msg_info "Starting nextExplorer" diff --git a/ct/qui.sh b/ct/qui.sh deleted file mode 100644 index 4984e1b7a..000000000 --- a/ct/qui.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env bash -source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func) -# Copyright (c) 2021-2026 community-scripts ORG -# Author: MickLesk (Canbiz) -# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE -# Source: https://github.com/autobrr/qui - -APP="Qui" -var_tags="${var_tags:-torrent}" -var_disk="${var_disk:-10}" -var_cpu="${var_cpu:-1}" -var_ram="${var_ram:-1024}" -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/local/bin/qui ]]; then - msg_error "No ${APP} Installation Found!" - exit - fi - if check_for_gh_release "Qui" "autobrr/qui"; then - msg_info "Stopping Service" - systemctl stop qui - msg_ok "Stopped Service" - - fetch_and_deploy_gh_release "qui" "autobrr/qui" "prebuild" "latest" "/tmp/qui" "qui_*_linux_x86_64.tar.gz" - - msg_info "Updating qui" - mv /tmp/qui/qui /usr/local/bin/qui - chmod +x /usr/local/bin/qui - rm -rf /tmp/qui - msg_ok "Updated qui" - - msg_info "Starting Service" - systemctl start qui - 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}:7476${CL}" diff --git a/frontend/public/json/flatnotes.json b/frontend/public/json/flatnotes.json new file mode 100644 index 000000000..bd45d3d51 --- /dev/null +++ b/frontend/public/json/flatnotes.json @@ -0,0 +1,35 @@ +{ + "name": "Flatnotes", + "slug": "flatnotes", + "categories": [ + 12 + ], + "date_created": "2026-01-15", + "type": "ct", + "updateable": true, + "privileged": false, + "interface_port": 8080, + "documentation": "https://github.com/dullage/flatnotes/wiki", + "website": "https://github.com/dullage/flatnotes", + "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/flatnotes.webp", + "config_path": "/opt/flatnotes/.env", + "description": "A self-hosted, database-less note-taking web app that utilises a flat folder of markdown files for storage.", + "install_methods": [ + { + "type": "default", + "script": "ct/flatnotes.sh", + "resources": { + "cpu": 1, + "ram": 1024, + "hdd": 4, + "os": "debian", + "version": "13" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [] +} diff --git a/frontend/public/json/qui.json b/frontend/public/json/qui.json deleted file mode 100644 index 1c9c8f722..000000000 --- a/frontend/public/json/qui.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "Qui", - "slug": "qui", - "categories": [ - 7 - ], - "date_created": "2026-01-13", - "type": "ct", - "updateable": true, - "privileged": false, - "interface_port": 7476, - "documentation": "https://github.com/autobrr/qui", - "website": "https://github.com/autobrr/qui", - "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/qui.webp", - "config_path": "/root/.config/qui/config.toml", - "description": "Qui is a modern, self-hosted web interface for managing multiple qBittorrent instances with support for 10k+ torrents. It provides a clean and responsive interface for monitoring and controlling your qBittorrent downloads across multiple servers.", - "install_methods": [ - { - "type": "default", - "script": "ct/qui.sh", - "resources": { - "cpu": 1, - "ram": 1024, - "hdd": 10, - "os": "debian", - "version": "13" - } - } - ], - "default_credentials": { - "username": null, - "password": null - }, - "notes": [] -} diff --git a/install/flatnotes-install.sh b/install/flatnotes-install.sh new file mode 100644 index 000000000..ee7a93ed0 --- /dev/null +++ b/install/flatnotes-install.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: luismco +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Source: https://github.com/dullage/flatnotes + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +fetch_and_deploy_gh_release "flatnotes" "dullage/flatnotes" +USE_UVX=YES setup_uv +setup_nodejs + +msg_info "Installing Backend" +cd /opt/flatnotes +$STD /usr/local/bin/uvx migrate-to-uv +$STD /usr/local/bin/uv sync +mkdir /opt/flatnotes/data +msg_ok "Installed Backend" + +msg_info "Installing Frontend" +cd /opt/flatnotes/client +$STD npm install +$STD npm run build +msg_ok "Installed Frontend" + + +msg_info "Creating Service" +cat </opt/flatnotes/.env +FLATNOTES_AUTH_TYPE='none' +FLATNOTES_PATH='/opt/flatnotes/data/' +#FLATNOTES_USERNAME='username' +#FLATNOTES_PASSWORD='password' +#FLATNOTES_SECRET_KEY='secret-key' +EOF +cat </etc/systemd/system/flatnotes.service +[Unit] +Description=Flatnotes +After=network.target + +[Service] +Type=simple +WorkingDirectory=/opt/flatnotes +EnvironmentFile=/opt/flatnotes/.env +ExecStart=/opt/flatnotes/.venv/bin/python -m uvicorn main:app --app-dir server --host 0.0.0.0 --port 8080 --proxy-headers +Restart=on-failure +RestartSec=10 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now flatnotes +msg_ok "Created Service" + +motd_ssh +customize +cleanup_lxc diff --git a/install/minthcm-install.sh b/install/minthcm-install.sh index a6eed1129..090a31135 100644 --- a/install/minthcm-install.sh +++ b/install/minthcm-install.sh @@ -12,8 +12,8 @@ catch_errors setting_up_container network_check update_os - -PHP_APACHE="YES" PHP_VERSION="8.2" PHP_MODULE="mysql,cli,redis" PHP_FPM="YES" setup_php +PHP_VERSION="8.2" +PHP_APACHE="YES" PHP_MODULE="mysql,cli,redis" PHP_FPM="YES" setup_php setup_composer msg_info "Enabling Apache modules (rewrite, headers)" diff --git a/install/nextexplorer-install.sh b/install/nextexplorer-install.sh index 8ed03263a..940cdec67 100644 --- a/install/nextexplorer-install.sh +++ b/install/nextexplorer-install.sh @@ -119,8 +119,9 @@ SHARES_ENABLED=true # SHARES_ALLOW_ANONYMOUS=true EOF chmod 600 /etc/nextExplorer/.env -$STD useradd -U -s /bin/bash -m -d /home/explorer explorer +$STD useradd -U -s /usr/sbin/nologin -m -d /home/explorer explorer chown -R explorer:explorer "$APP_DIR" /etc/nextExplorer +sed -i "\|version|s|$(jq -cr '.version' ${APP_DIR}/package.json)|$(cat ~/.nextexplorer)|" "$APP_DIR"/package.json msg_ok "Configured nextExplorer" msg_info "Creating nextExplorer Service" @@ -131,6 +132,8 @@ After=network.target [Service] Type=simple +User=explorer +Group=explorer WorkingDirectory=/opt/nextExplorer/app EnvironmentFile=/etc/nextExplorer/.env ExecStart=/usr/bin/node ./src/app.js diff --git a/install/qui-install.sh b/install/qui-install.sh deleted file mode 100644 index 8e45ed000..000000000 --- a/install/qui-install.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env bash - -# Copyright (c) 2021-2026 community-scripts ORG -# Author: MickLesk (Canbiz) -# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE -# Source: https://github.com/autobrr/qui - -source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" -color -verb_ip6 -catch_errors -setting_up_container -network_check -update_os - -fetch_and_deploy_gh_release "qui" "autobrr/qui" "prebuild" "latest" "/usr/local/bin" "qui_*_linux_x86_64.tar.gz" -chmod +x /usr/local/bin/qui -ln -sf /usr/local/bin/qui /usr/bin/qui -ln -sf /usr/local/bin/qui /opt/qui - -msg_info "Creating Qui Service" -cat </etc/systemd/system/qui.service -[Unit] -Description=Qui - qBittorrent Web UI -After=network-online.target -Wants=network-online.target - -[Service] -Type=simple -ExecStart=/usr/local/bin/qui serve -Restart=on-failure -RestartSec=5s - -[Install] -WantedBy=multi-user.target -EOF -systemctl enable -q --now qui -msg_ok "Created Qui Service" - -motd_ssh -customize -cleanup_lxc