Consolidate all paths to plugin flash dir, fix watchdog 7.3 triggers

- Move SCRIPTS_DIR/DATA_DIR/STATE_DIR from appdata to /boot/config/plugins/varaverk
- All state files now in STATE_DIR (no more /tmp or /boot/config root writes)
- Bootstrap: Gitea-first clone with GitHub fallback, no array dependency
- varaverk.cfg seeded with Gitea connection settings
- .gitignore: add State_Files/, varaverk.cfg, varaverk-*.txz
- Partnership/transcode/fallback scripts use STATE_DIR variables
- PHP config.php: DATA_DIR/STATE_DIR constants, VV_SETUP_STATE_FILE dynamic
- deploy.sh PROD_ROOT updated to plugin flash dir

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gmer4Lfe
2026-05-31 13:30:20 -04:00
co-authored by Claude Sonnet 4.6
parent 9191a54637
commit fb0530deba
40 changed files with 1609 additions and 262 deletions
+141 -131
View File
@@ -2,18 +2,26 @@
<!DOCTYPE PLUGIN [
<!ENTITY name "varaverk">
<!ENTITY author "gmer4lfe">
<!ENTITY version "2026.05.30">
<!ENTITY version "2026.05.31">
<!ENTITY sha256 "932468c8a114134dea3062f2810a7ca5a7b1168e1e78d0195c41c61b86db7728">
<!ENTITY launch "varaverk/monitor">
<!ENTITY github "https://github.com/FailedProxy/Varaverk">
<!ENTITY branch "main">
<!ENTITY cfgdir "/boot/config/plugins/varaverk">
<!ENTITY plugdir "/usr/local/emhttp/plugins/varaverk">
<!ENTITY pkg "varaverk-&version;-noarch-1.txz">
]>
<PLUGIN name="&name;" author="&author;" version="&version;" launch="&launch;"
support="https://github.com/FailedProxy/Varaverk/issues"
icon="/plugins/varaverk/icons/varaverk.png">
<CHANGES>
###2026.05.31
- Packaged release: web files now ship as a .txz that Unraid reinstalls to RAM on every boot
- Survives reboots with zero manual steps (no symlink, no go script) — fixes plugin vanishing after OS upgrades
- Scripts are git-cloned to appdata on first install; web files stay on flash (~200KB)
- Updates handled in-UI (git pull); the plugin no longer pulls on every boot
###2026.05.30
- First-run setup wizard: auto-detects hostname, creates master.conf + host conf from templates
- Scheduler setup mode: after wizard, master.conf and host conf open sequentially with forced save flow
@@ -33,143 +41,153 @@
</CHANGES>
<!--
── Install / Update ────────────────────────────────────────────────────────────
Runs on first install and on every plugin update.
Clones the repo on fresh install; pulls latest on update.
Array must be started — appdata must be available.
── 1. Web files package (runs on every boot) ──────────────────────────────────
unRAID runs `plugin install` on every .plg at boot, BEFORE the array mounts.
The .txz lives on flash, so this installs the PHP/JS UI to RAM in time — and the
disks_mounted event hooks inside it are then present when the array starts, so
cron is rebuilt automatically. No Method attr = treated as "install" = every boot.
Download is skipped when the .txz is already on flash with a matching SHA256, so
this also works offline / for a local install (copy the .txz into &cfgdir;).
────────────────────────────────────────────────────────────────────────────────
-->
<FILE Name="&cfgdir;/install.sh" Run="/bin/bash" Method="install update">
<FILE Name="&cfgdir;/&pkg;" Run="/sbin/upgradepkg --install-new --reinstall">
<URL>https://github.com/FailedProxy/Varaverk/releases/download/&version;/&pkg;</URL>
<SHA256>&sha256;</SHA256>
</FILE>
<!--
── 2. Scripts bootstrap (first install only) ──────────────────────────────────
Clones the repo directly into the plugin config dir on flash (/boot/config/plugins/varaverk).
No array dependency — scripts live on flash (64GB NVMe) and are available at boot.
Uses git init+fetch+reset so the clone works into the non-empty cfgdir (varaverk.cfg,
varaverk-*.txz etc. are already there). Never auto-pulls — updates via the UI git pull.
Clone source priority:
1. Gitea (internal) — reads settings from varaverk.cfg; detects container IP at runtime
2. GitHub (public) — HTTPS fallback if Gitea is unreachable
────────────────────────────────────────────────────────────────────────────────
-->
<FILE Run="/bin/bash" Method="install">
<INLINE>
<![CDATA[
#!/bin/bash
PLUGIN="varaverk"
GITHUB="https://github.com/FailedProxy/Varaverk"
BRANCH="main"
CFG_DIR="/boot/config/plugins/$PLUGIN"
CFG_FILE="$CFG_DIR/varaverk.cfg"
WEB_DIR="/usr/local/emhttp/plugins/$PLUGIN"
GITHUB="https://github.com/FailedProxy/Varaverk"
BRANCH="main"
LOG="$CFG_DIR/install.log"
mkdir -p "$CFG_DIR"
log() { echo "[$(date '+%H:%M:%S')] $*" | tee -a "$LOG"; }
log "=== Varaverk install/update ==="
# Unraid only
if [[ ! -f /etc/unraid-version ]]; then
log "ERROR: not running on Unraid — aborting"
exit 1
fi
# Read SCRIPTS_DIR from cfg if present
if [[ -f "$CFG_FILE" ]]; then
_sd=$(grep -oP '(?<=SCRIPTS_DIR=")[^"]+' "$CFG_FILE" 2>/dev/null)
[[ -n "$_sd" ]] && SCRIPTS_DIR="$_sd"
fi
SCRIPTS_DIR="${SCRIPTS_DIR:-/mnt/user/appdata/Varaverk}"
# Scripts live in the plugin dir on flash — no array needed.
SCRIPTS_DIR="$CFG_DIR"
CONF_DIR="$SCRIPTS_DIR/Configurations"
# Array must be started — appdata must be available
if ! df --output=fstype /mnt/user 2>/dev/null | grep -q 'shfs'; then
log "Array not started — cannot install to appdata"
log "Start the array then reinstall, or wait for next boot"
exit 0
fi
# Clone or update repo
if [[ ! -d "$SCRIPTS_DIR/.git" ]]; then
log "Cloning $GITHUB ($BRANCH) → $SCRIPTS_DIR"
if ! git clone --branch "$BRANCH" "$GITHUB" "$SCRIPTS_DIR" >> "$LOG" 2>&1; then
log "ERROR: git clone failed — check internet access and GitHub URL"
exit 1
fi
log "Clone complete"
else
log "Updating repo in $SCRIPTS_DIR"
git -C "$SCRIPTS_DIR" pull --ff-only origin "$BRANCH" >> "$LOG" 2>&1 \
&& log "Pull complete" \
|| log "WARNING: git pull failed — repo may have local modifications"
fi
# Sanity check — Plugin/unraid must exist after clone
if [[ ! -d "$SCRIPTS_DIR/Plugin/unraid" ]]; then
log "ERROR: Plugin/unraid not found in cloned repo — unexpected repo structure"
exit 1
fi
# Symlink web files
if [[ -L "$WEB_DIR" ]]; then
rm "$WEB_DIR"
elif [[ -d "$WEB_DIR" ]]; then
log "WARNING: $WEB_DIR is a real directory — not replacing (remove manually if needed)"
fi
if [[ ! -e "$WEB_DIR" ]]; then
ln -s "$SCRIPTS_DIR/Plugin/unraid" "$WEB_DIR"
log "Symlinked: $WEB_DIR → $SCRIPTS_DIR/Plugin/unraid"
fi
# Write varaverk.cfg if not present
# Seed varaverk.cfg with defaults (SCRIPTS_DIR + Gitea settings) if not present.
if [[ ! -f "$CFG_FILE" ]]; then
printf 'SCRIPTS_DIR="%s"\n' "$SCRIPTS_DIR" > "$CFG_FILE"
log "Created varaverk.cfg (SCRIPTS_DIR=$SCRIPTS_DIR)"
cat > "$CFG_FILE" <<'CFGEOF'
SCRIPTS_DIR="/boot/config/plugins/varaverk"
GITEA_CONTAINER="Gitea"
GITEA_REPO_PATH="FailedProxy/Varaverk.git"
GITEA_SSH_KEY="/root/.ssh/unraid_gitea"
SSH_PORT="221"
CFGEOF
log "seeded varaverk.cfg"
fi
# Create Configurations dir if git clone didn't
mkdir -p "$CONF_DIR"
# Read Gitea settings from varaverk.cfg (allows override without editing .plg).
_read_cfg() { grep -oP "(?<=^${1}=\")[^\"]*" "$CFG_FILE" 2>/dev/null || echo "${2}"; }
GITEA_CONTAINER=$(_read_cfg GITEA_CONTAINER "Gitea")
GITEA_REPO_PATH=$(_read_cfg GITEA_REPO_PATH "FailedProxy/Varaverk.git")
GITEA_SSH_KEY=$(_read_cfg GITEA_SSH_KEY "/root/.ssh/unraid_gitea")
SSH_PORT=$(_read_cfg SSH_PORT "221")
# Bootstrap master.conf from template on first install
if [[ ! -f "$CONF_DIR/master.conf" ]]; then
if [[ -f "$SCRIPTS_DIR/Configurations/master.conf.template" ]]; then
cp "$SCRIPTS_DIR/Configurations/master.conf.template" "$CONF_DIR/master.conf"
log "Created master.conf from template — fill in HOST1 and HOST2 to continue"
else
log "WARNING: master.conf.template not found — master.conf not created"
# Clone on first install only; never auto-pull (updates via the UI git pull).
if [[ ! -d "$SCRIPTS_DIR/.git" ]]; then
log "initialising repo in $SCRIPTS_DIR ($BRANCH)..."
# Locate Gitea: local container → local IP; else Tailscale; else fall back to GitHub.
GITEA_IP=""
if command -v docker >/dev/null 2>&1 && \
docker ps --format "{{.Names}}" 2>/dev/null | grep -q "^${GITEA_CONTAINER}$"; then
GITEA_IP=$(hostname -I | awk '{print $1}')
log "Gitea running locally — using $GITEA_IP"
elif command -v tailscale >/dev/null 2>&1; then
# Try each known peer until we find one hosting Gitea
while IFS= read -r peer_ip; do
if ssh -i "$GITEA_SSH_KEY" -p "$SSH_PORT" \
-o ConnectTimeout=3 -o StrictHostKeyChecking=no \
-o BatchMode=yes "git@${peer_ip}" info 2>/dev/null | grep -q "varaverk\|Gitea\|gitea"; then
GITEA_IP="$peer_ip"
log "Gitea found on Tailscale peer $GITEA_IP"
break
fi
done < <(tailscale status --json 2>/dev/null | \
python3 -c "import json,sys; d=json.load(sys.stdin); \
[print(v['TailscaleIPs'][0]) for v in d.get('Peer',{}).values() \
if v.get('TailscaleIPs')]" 2>/dev/null)
fi
# init-in-place — git clone would fail because the dir already has files.
git -C "$SCRIPTS_DIR" init >> "$LOG" 2>&1
CLONED=false
if [[ -n "$GITEA_IP" && -f "$GITEA_SSH_KEY" ]]; then
GITEA_URL="ssh://git@${GITEA_IP}:${SSH_PORT}/${GITEA_REPO_PATH}"
log "trying Gitea: $GITEA_URL"
git -C "$SCRIPTS_DIR" remote add origin "$GITEA_URL" >> "$LOG" 2>&1
if GIT_SSH_COMMAND="ssh -i $GITEA_SSH_KEY -p $SSH_PORT -o StrictHostKeyChecking=no" \
GIT_TERMINAL_PROMPT=0 \
git -C "$SCRIPTS_DIR" fetch --depth=1 origin "$BRANCH" >> "$LOG" 2>&1; then
git -C "$SCRIPTS_DIR" reset --hard FETCH_HEAD >> "$LOG" 2>&1
git -C "$SCRIPTS_DIR" branch -M "$BRANCH" >> "$LOG" 2>&1
log "scripts installed from Gitea ($GITEA_IP)"
CLONED=true
else
log "Gitea fetch failed — falling back to GitHub"
git -C "$SCRIPTS_DIR" remote remove origin >> "$LOG" 2>&1 || true
fi
fi
if [[ "$CLONED" == false ]]; then
log "trying GitHub: $GITHUB"
git -C "$SCRIPTS_DIR" remote add origin "$GITHUB" >> "$LOG" 2>&1
if GIT_TERMINAL_PROMPT=0 \
git -C "$SCRIPTS_DIR" fetch --depth=1 origin "$BRANCH" >> "$LOG" 2>&1; then
git -C "$SCRIPTS_DIR" reset --hard FETCH_HEAD >> "$LOG" 2>&1
git -C "$SCRIPTS_DIR" branch -M "$BRANCH" >> "$LOG" 2>&1
log "scripts installed from GitHub"
CLONED=true
else
log "WARNING: both Gitea and GitHub failed — scripts not installed, retry when network is up"
exit 0
fi
fi
else
log "repo present — leaving scripts untouched (update from the UI)"
fi
log "Install complete — open Varaverk in Unraid to complete setup"
log "→ Plugins → Varaverk (or navigate to Settings → Utilities → Varaverk)"
# Seed master.conf from template if absent.
mkdir -p "$CONF_DIR"
if [[ ! -f "$CONF_DIR/master.conf" && -f "$SCRIPTS_DIR/Deployment/conf_templates/master.conf" ]]; then
cp "$SCRIPTS_DIR/Deployment/conf_templates/master.conf" "$CONF_DIR/master.conf"
log "seeded master.conf from template"
fi
log "install step complete"
]]>
</INLINE>
</FILE>
<!--
── Boot (every boot) ───────────────────────────────────────────────────────────
Fast idempotent check — recreates the web symlink if it disappeared.
No git operations. Safe to run before the array is fully started.
── 3. Remove ───────────────────────────────────────────────────────────────────
Stops background scripts, removes cron, the installed package, and flash config.
Scripts/conf in appdata are left intact (delete manually for a full wipe).
────────────────────────────────────────────────────────────────────────────────
-->
<FILE Name="&cfgdir;/boot.sh" Run="/bin/bash">
<INLINE>
<![CDATA[
#!/bin/bash
PLUGIN="varaverk"
CFG_FILE="/boot/config/plugins/$PLUGIN/varaverk.cfg"
WEB_DIR="/usr/local/emhttp/plugins/$PLUGIN"
# Read SCRIPTS_DIR
if [[ -f "$CFG_FILE" ]]; then
_sd=$(grep -oP '(?<=SCRIPTS_DIR=")[^"]+' "$CFG_FILE" 2>/dev/null)
fi
SCRIPTS_DIR="${_sd:-/mnt/user/appdata/Varaverk}"
# Only act if source exists (array started) and symlink is missing
if [[ -d "$SCRIPTS_DIR/Plugin/unraid" ]] && [[ ! -e "$WEB_DIR" ]]; then
[[ -L "$WEB_DIR" ]] && rm "$WEB_DIR"
ln -s "$SCRIPTS_DIR/Plugin/unraid" "$WEB_DIR"
fi
]]>
</INLINE>
</FILE>
<!--
── Remove ──────────────────────────────────────────────────────────────────────
Removes the web symlink. Scripts and conf in appdata are left intact.
────────────────────────────────────────────────────────────────────────────────
-->
<FILE Name="&cfgdir;/remove.sh" Run="/bin/bash" Method="remove">
<FILE Run="/bin/bash" Method="remove">
<INLINE>
<![CDATA[
#!/bin/bash
@@ -178,44 +196,36 @@ CFG_DIR="/boot/config/plugins/$PLUGIN"
CFG_FILE="$CFG_DIR/varaverk.cfg"
CRON_FILE="$CFG_DIR/varaverk.cron"
WEB_DIR="/usr/local/emhttp/plugins/$PLUGIN"
log() { echo "[Varaverk remove] $*"; }
# Read SCRIPTS_DIR so we can locate running scripts
if [[ -f "$CFG_FILE" ]]; then
_sd=$(grep -oP '(?<=SCRIPTS_DIR=")[^"]+' "$CFG_FILE" 2>/dev/null)
fi
SCRIPTS_DIR="${_sd:-/mnt/user/appdata/Varaverk}"
[[ -f "$CFG_FILE" ]] && _sd=$(grep -oP '(?<=SCRIPTS_DIR=")[^"]+' "$CFG_FILE" 2>/dev/null)
SCRIPTS_DIR="${_sd:-$CFG_DIR}"
# ── Stop continuous background scripts ───────────────────────────────────────
# fallback.sh manages its own lock — use --stop for clean shutdown
# Stop continuous background scripts.
if [[ -f "$SCRIPTS_DIR/Fallback/fallback.sh" ]]; then
bash "$SCRIPTS_DIR/Fallback/fallback.sh" --stop 2>/dev/null && \
log "fallback.sh stopped" || true
bash "$SCRIPTS_DIR/Fallback/fallback.sh" --stop 2>/dev/null && log "fallback.sh stopped" || true
fi
# Kill any remaining Varaverk background processes (watchdog orchestrator, etc.)
pkill -f "run_job.sh" 2>/dev/null || true
pkill -f "watchdog_orchestrator.sh" 2>/dev/null || true
# ── Remove cron entries ───────────────────────────────────────────────────────
# Remove cron entries.
if [[ -f "$CRON_FILE" ]]; then
rm -f "$CRON_FILE"
/usr/local/sbin/update_cron 2>/dev/null || true
log "Cron entries removed"
log "cron removed"
fi
# Remove legacy direct cron file if it exists
rm -f /etc/cron.d/varaverk
# ── Remove web symlink ────────────────────────────────────────────────────────
[[ -L "$WEB_DIR" ]] && rm -f "$WEB_DIR" && log "Web symlink removed"
# Remove the installed package (and its RAM files).
removepkg "$PLUGIN" 2>/dev/null || true
[[ -L "$WEB_DIR" ]] && rm -f "$WEB_DIR"
[[ -d "$WEB_DIR" ]] && rm -rf "$WEB_DIR"
log "web files removed"
# ── Remove plugin config from flash ──────────────────────────────────────────
# Remove flash config (incl. cached .txz).
rm -rf "$CFG_DIR"
log "Plugin config removed from flash"
log "Done. Scripts and conf in $SCRIPTS_DIR are preserved."
log "To fully remove: delete $SCRIPTS_DIR manually."
log "flash config removed"
log "done — scripts/conf in $SCRIPTS_DIR preserved (delete manually for full wipe)"
]]>
</INLINE>
</FILE>