Commit Graph
100 Commits
Author SHA1 Message Date
Gmer4LfeandClaude Sonnet 4.6 55a38b6b74 fix: prune dangling images after docker_update.sh pulls
docker_update_remaining.sh already pruned; docker_update.sh (daily)
did not — orphaned images accumulated with every daily update run.
Same prune pattern as docker_update_remaining.sh.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 14:59:57 -04:00
Gmer4LfeandClaude Sonnet 4.6 44f33da454 fix: set vm.overcommit_memory=1 at array start for Redis
Redis warns and can fail background saves without this. Applied via
inotify_tuning.sh which already handles kernel parameter tuning at
array start. Resets on each reboot — reapplied automatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 14:55:25 -04:00
Gmer4LfeandClaude Sonnet 4.6 070f9caf7f rename: SYS_WATCHDOG_FAILED_FILE → DOCKER_WATCHDOG_FAILED_FILE
Skip list belongs to docker_watchdog, not stability_watchdog (legacy
naming from when docker+system were the only two watchdogs). Rename
variable and physical file system_watchdog_failed.db →
docker_watchdog_failed.db across all files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 14:51:37 -04:00
Gmer4LfeandClaude Sonnet 4.6 9d6772fbd6 fix: correct state file ownership and function naming across watchdogs
stability_watchdog: remove SYS_WATCHDOG_FAILED_FILE from state file
touch list — skip list is owned by docker_watchdog, not stability.

docker_watchdog: rename check_system_watchdog_state →
check_resource_watchdog_state (reads RW_STATE_FILE from resource_watchdog,
not SYS_WATCHDOG_STATE_FILE from stability_watchdog). Update all comments
and state file docs to reflect correct ownership.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 14:46:18 -04:00
Gmer4LfeandClaude Sonnet 4.6 cce6fc5b65 fix: clear daemon_confirmed_down unconditionally when daemon healthy
Previously only cleared inside the strikes>0 block. After a reboot,
strikes reset to 0 but the flag persists on flash — daemon could be
healthy but flag stays true, causing stability_watchdog to keep striking.

Now cleared on every healthy docker info check regardless of strike count.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 14:40:08 -04:00
Gmer4LfeandClaude Sonnet 4.6 f6fb3add77 refactor: delegate Docker daemon escalation from stability to docker_watchdog
docker_watchdog now writes daemon_confirmed_down=true to its state file
when restart is attempted and daemon is still unresponsive. Clears the
flag on recovery.

stability_watchdog removes the duplicate CRITICAL daemon check (which
bypassed all strikes, all abort conditions, and had its own rc.docker
restart). Replaced with a standard strike check reading the
daemon_confirmed_down flag from docker_watchdog's state file.

Result: docker_watchdog owns all daemon restart logic. stability_watchdog
escalates to reboot only after N consecutive strike cycles confirming the
daemon is truly unrecoverable — same pattern as all other standard checks.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 14:38:03 -04:00
Gmer4LfeandClaude Sonnet 4.6 9c68429e25 fix: remove container check from stability_watchdog, add USB boot warning
stability_watchdog: container health is owned by docker_watchdog — rebooting
when docker_watchdog skip-lists a container creates a reboot loop. Removed
SYS_WATCHDOG_CHECK_CONTAINERS check entirely. docker_watchdog handles
strikes, restart attempts, skip-listing, and notifications.

varaverk.plg: warn on USB/removable boot device at install time. Plugin is
designed for internal NVMe/SSD boot. Warning is non-blocking but clear.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 14:30:48 -04:00
Gmer4LfeandClaude Sonnet 4.6 b9b1d20499 safeguard: skip watchdog cycle if array not started
Exits cleanly before startup grace check if /mnt/user is not mounted
as shfs. Prevents watchdogs running against Docker/storage that isn't
available, and blocks false-positive reboots when array is stopped.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 14:14:00 -04:00
Gmer4LfeandClaude Sonnet 4.6 cbf8593225 docs: remove bind-propagation=shared, document runc v1.3.5 crash
runc v1.3.5 (Docker 29.x / Unraid 7.3+) crashes on bind-propagation=shared
with any container — not GPU-specific. Ramdisk tmpfs is already MS_SHARED
at kernel level; propagation is automatic and the option is unnecessary.

- Remove bind-propagation=shared from all example Extra Parameters
- Update "Why shared Is Required" → "Mount Propagation — Unraid 7.3+"
- Update GPU troubleshooting section to cover the general runc crash
- Verify commands updated (no longer checking for Propagation: shared)
- Historical notes preserved explaining why it existed before

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 14:08:17 -04:00
Gmer4LfeandClaude Sonnet 4.6 cd2fd1af70 fix: remove bind-propagation=shared from mount instructions
runc v1.3.5 (Docker 29.x / Unraid 7.3+) rejects bind-propagation=shared
on symlink sources with: open /proc/self/mountinfo: no such file or directory.
The ramdisk tmpfs is already MS_SHARED at the kernel level — propagation is
inherited automatically and does not need to be specified in Docker.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 13:56:59 -04:00
Gmer4LfeandClaude Sonnet 4.6 e0fdaa1868 fix: set upstream tracking branch in bootstrap after clone
git pull would fail on first run after install without tracking info.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 13:52:41 -04:00
Gmer4LfeandClaude Sonnet 4.6 765442c25d fix: update all script paths in user_script_plug-in.sh to plugin flash dir
228 path references updated from /mnt/user/appdata/Varaverk/ to
/boot/config/plugins/varaverk/. PATHS header block updated to match.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 13:51:07 -04:00
Gmer4LfeandClaude Sonnet 4.6 da699b54fa req: internal NVMe boot required, all paths consolidated on flash
Plugin folder /boot/config/plugins/varaverk is the single home for
scripts, data, and state. Available at boot before array mounts.
USB boot is not a supported configuration.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 13:38:52 -04:00
Gmer4LfeandClaude Sonnet 4.6 5234b79210 fix: revert public defaults to appdata, flash paths are user-local only
Bootstrap varaverk.cfg default and conf template default back to
/mnt/user/appdata/Varaverk — safe for USB boot users. Flash paths
(/boot/config/plugins/varaverk) are set in the user's gitignored
personal configs and don't affect public installs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 13:36:06 -04:00
Gmer4LfeandClaude Sonnet 4.6 ad1890109a build: bump version 2026.05.31, update sha256 for local txz
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 13:33:59 -04:00
Gmer4LfeandClaude Sonnet 4.6 fb0530deba 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>
2026-05-31 13:30:20 -04:00
Gmer4Lfe 9191a54637 Fix ssh_setup.sh: HOST_CONF path missing Configurations/ subdirectory
Was looking for host1.conf at SCRIPTS_ROOT/host1.conf instead of
SCRIPTS_ROOT/Configurations/host1.conf — causing the 'host1.conf not found'
warning and leaving HOST1_SSH_KEY unwritten after key generation.
2026-05-30 21:31:46 -04:00
Gmer4Lfe 2989cefb79 Redesign Cancel/Delete Keys in Partnership Actions
onboard_cancel.sh:
- --direction=h1 (default): remove HOST1's key from HOST2 + delete local pair
- --direction=h2: remove HOST2's key from HOST1's authorized_keys (by hostname match)
- --direction=both: both directions (used by Cancel button at phase 1)

pages/partnership.php:
- Cancel button: phase 1 only, runs --direction=both (full undo)
- Delete Keys (🗑): available at all phases, expands inline panel showing
  HOST1→HOST2 and HOST2→HOST1 as separate removal buttons with descriptions
- _vvDeleteKeys toggle state persists across polls alongside _vvOnboarding
- vvPtShowDeleteKeys / vvPtHideDeleteKeys top-level toggle fns
- vvPtDeleteH1 / vvPtDeleteH2 targeted removal fns
2026-05-30 21:29:20 -04:00
Gmer4Lfe 1956b6b068 Fix: local keyword outside function in --local-only block
flag_key was declared with 'local' at script top level, which is only
valid inside bash functions. This left flag_key empty, writing '=true'
(malformed) to setup.db instead of 'HOST1_LOCAL_DONE=true'.
Changed to a plain variable assignment.
2026-05-30 21:20:56 -04:00
Gmer4Lfe 5bd8d13e66 Terminal link: use window.location.hostname (local IP) not Tailscale 2026-05-30 21:16:07 -04:00
Gmer4Lfe e449e1f954 Partnership Actions: full redesign with stepped onboard cards
- Single '▶ Onboard' button per unprovisioned remote → expands that card
  to show Step 1 (terminal link + click-to-copy command) and Step 2 (Push Conf)
- Onboard state persists across 10s poll re-renders via top-level _vvOnboarding map
  and _vvPtReload hook set by the IIFE
- Phase 1 complete: amber 'SSH ready' pill + Tailscale IP + Phase 2 manual button
- Phase 2 complete: green 'Active' pill + date + IP + uptime + unRAID version + state
- Compact compact '○ Not provisioned' + Reset button when not in onboard mode
- Removed vvPtPhase1 (replaced by vvPtStartOnboard toggle)
- vvPtStartOnboard / vvPtEndOnboard are top-level functions
2026-05-30 21:13:31 -04:00
Gmer4Lfe 4449bfc646 Partnership phase 0: terminal link + clickable command block
At phase 0, show below the buttons:
- 'Open Terminal' link using HOST1's Tailscale IP (/webterminal/ttyd/)
- Clickable command code block (click to copy) with the Phase 1 script path
- Note that tab auto-updates on next poll when the script completes

Tailscale IP comes from selfNode.ts_ip already in the API response.
2026-05-30 21:02:27 -04:00
Gmer4Lfe 95fd38799d Phase 1: resilient SSH handling + Push Conf button
partnership_onboard.sh (--phase1-only):
- Test if SSH already works first (BatchMode) — skip ssh-copy-id if yes
- If ssh-copy-id fails (no TTY in background): soft-fail, generate key locally,
  print pubkey for manual install, write HOST2_KEY_READY=true, run local setup
- Only skip conf push if SSH truly unavailable; otherwise proceeds normally
- Exit 0 with clear manual-step instructions instead of hard failure

include/partnership.php:
- Read HOST2_KEY_READY from setup.db; expose as key_ready on remote nodes

pages/partnership.php:
- Node card: amber "Key generated · install on HOST2 then Push Conf" badge
  when key_ready=true and phase=0
- "Push Conf (key installed)" button appears when key_ready=true — runs
  --phase1-only --skip-ssh (assumes user manually did ssh-copy-id)
- vvPtPushConf() top-level function
2026-05-30 20:27:30 -04:00
Gmer4Lfe 4aaa3c507a Monitor partner card: onboard phase badges (re-add) 2026-05-30 20:08:23 -04:00
Gmer4Lfe 192664605b Revert monitor onboard indicator — belongs on Partnership page only 2026-05-30 20:06:11 -04:00
Gmer4Lfe c97a30b9c4 Monitor partner card: onboard phase indicator per remote host
vv_partner_state() now reads setup.db and adds onboard_phase (0/1/2/null)
to each host entry.

Partner card JS renders a badge under the hostname for remote hosts that
haven't completed Phase 2: amber "Awaiting onboard" (phase 1) or grey
"Not provisioned" (phase 0). Phase 2 complete shows nothing extra.
2026-05-30 20:04:32 -04:00
Gmer4Lfe 7d4994f317 Local onboard: set PARTNERSHIP_ENABLED=true in master.conf + push
When HOST1 completes its local setup (--onboard --local-only), enable the
partnership in master.conf so sync scripts start functioning immediately.
Pushes the updated master.conf to all listed hosts via vv_push_master_conf().
2026-05-30 20:00:54 -04:00
Gmer4Lfe d1ee880586 HOST1 completes local onboard independently during Phase 1
partnership_manager.sh:
- --local-only flag for --onboard: skips remote pre-flight, WebUI reconfig,
  state push; runs FolderView3 folder creation + writes HOST1_LOCAL_DONE=true
  to setup.db + pushes it; exits without writing ACTIVE (partnership not yet
  established until Phase 2)

partnership_onboard.sh:
- Phase 1 exit now runs partnership_manager.sh --onboard --local-only after
  SSH + conf push, so HOST1 is fully configured on its own side before Phase 2

include/partnership.php:
- vv_pt_nodes() reads HOST1_LOCAL_DONE from setup.db; exposes as local_done
  on the self node (null for remote nodes)

pages/partnership.php:
- Self node card shows green "Local setup complete · waiting for partner"
  badge when local_done=true
- Actions: "Complete HOST1 Setup" button appears when HOST1 hasn't run local
  setup yet but HOST2 is already at phase 1 — lets user trigger it manually
- vvPtLocalSetup() top-level function calls partnership_manager.sh via run.php
2026-05-30 19:55:56 -04:00
Gmer4Lfe b59b94099a Partnership: handle empty run.php response gracefully
If run.php returns an empty body (transient nginx/PHP-FPM issue), the script
still runs via nohup. Treat empty response as ok instead of throwing a
JSON parse error that misleads the user into thinking the action failed.
2026-05-30 18:45:24 -04:00
Gmer4Lfe dfc24e37c0 Add Phase 1 cancel: remove SSH keys from both sides + reset state
onboard_cancel.sh:
- SSHes HOST2 while key still valid: removes HOST1 pubkey from authorized_keys
  and clears HOST2_PHASE* from setup.db on the remote side
- Deletes local private + public key pair
- Clears HOST2_PHASE* from local setup.db
- Graceful if HOST2 unreachable (local side still cleaned up)

partnership.php:
- Cancel button (warn style, slightly dimmed) at phase 0 and phase 1
- vvPtCancel() top-level function, calls onboard_cancel.sh via run.php
2026-05-30 18:33:56 -04:00
Gmer4Lfe c7e81edf4d Partnership: move action fns to top-level scope, remove window. approach
window.fn = inside an IIFE is not reliable in all script-loading contexts.
Move vvPtPhase1/2, vvPtOnboard, vvPtOffboard and their _vvPtRun helper
above the IIFE as plain top-level function declarations — unconditionally
global and reachable from onclick= attributes.
2026-05-30 18:24:41 -04:00
Gmer4Lfe be5332d0a4 Partnership: fix onclick functions not accessible outside IIFE
Tab pages use full page reloads (not AJAX) — function declarations inside
the IIFE are not in global scope, so onclick= attributes fail silently.

Fix: assign all onclick-callable functions to window.*
Replace vvRunById() calls with direct fetch (vvRunById is also IIFE-scoped
in scheduler.php, unavailable in the partnership tab context).
Add .catch() handlers so network/parse errors surface as alerts.
2026-05-30 18:21:31 -04:00
Gmer4Lfe a5755921ab Two-phase onboard + partner card enhancements
partnership_onboard.sh:
- --phase1-only (OWNER): SSH key exchange + conf push only; safe to run
  before HOST2 has Varaverk installed; writes HOST2_PHASE1_DONE to setup.db
- --phase2-only (OWNER): skips SSH, runs Steps 2-9 (containers, arr stack,
  onboard, arr sync, conf push); writes HOST2_PHASE2_DONE to setup.db
- Mirror path: after SSH setup, SSHes OWNER and fires --phase2-only in
  background (nohup); reads OWNER's SCRIPTS_DIR from varaverk.cfg first;
  falls back to manual instruction if SSH fails

partnership.php (include): vv_pt_nodes() reads setup.db and exposes
onboard_phase (0/1/2) per remote node

partnership.php (page): phase-aware Actions section per partner host;
node cards show phase badge (not provisioned / awaiting onboard / done);
Phase 1 and Phase 2 buttons call run.php with extra_args

monitor.php: partner card logo (top-right), CPU thread count, RAM total GB,
unRAID version row in remote stats grid
2026-05-30 18:12:49 -04:00
Gmer4Lfe 3dd867c684 Fix fallback state key: FAILOVER → FALLBACK (was never matching) 2026-05-30 17:26:09 -04:00
Gmer4Lfe 1e9d8bc75b Fallback card: rich state display with tiers, strikes, disabled/suspended
include/monitor.php: vv_fallback_state() now returns:
  enabled, check_interval, handback_strikes, handback_strikes_required,
  partnership_suspended, partner_lost_at, partnership_required,
  partnership_suspend_after — all read from state file + conf vars.

pages/monitor.php: fallback card render rebuilt:
  Disabled: clear message with how to enable
  Suspended: partnership inactive with elapsed time
  FAILOVER: outage duration + T1/T2/T3/T4 tier badges (active=green,
    pending=dark) + handback strike progress dots (●●○) when remote
    comes back and strikes are counting
  NO_INTERNET/DARK: short contextual line
  NORMAL: quiet "monitoring · 30s · partnership gated" meta line
  Accent border: disabled/suspended → warn, NORMAL → ok, FAILOVER → err
2026-05-30 17:24:55 -04:00
Gmer4Lfe 084dc819d9 Hide scrollbar on scripts card inner list div 2026-05-30 17:18:56 -04:00
Gmer4Lfe d56b02e410 Monitor: card icons + status accent borders
varaverk.css:
  .vv-ico — icon wrapper (inline-flex, opacity 0.38, flex-shrink:0)
  .vv-accent-ok/warn/err — left border colour overrides for state cards
  Smooth 0.5s transition on border-left-color for all monitor cards

monitor.php:
  All 14 card headers now have inline SVG icons:
    System (existing server), Power (existing bolt), CPU (chip+pins),
    Memory (RAM stick), Network (switch tree), Scripts (terminal),
    Fallback (shield), Partner (two servers linked), Containers (layers),
    GPU (PCIe card), Transcode (film→encode→strip), Streams (play ▶),
    Watchdog (eye), Parity (✓ circle), Pools (cylinder), Array (drive stack)

  Status accent borders applied by JS after each render:
    Fallback — ok:NORMAL, err:FAILOVER, warn:NO_INTERNET/DARK
    Partner  — ok:any remote online, warn:all offline
    Watchdog — ok:healthy, err:reboots/OOM/daemon, warn:other issues
    Array    — ok:STARTED, err:any other state
2026-05-30 17:08:59 -04:00
Gmer4Lfe da3d402f1a Revert "git_pull_execute: GitHub fallback when GITEA_REPO_PATH is empty"
This reverts commit 9a26478498.
2026-05-30 16:56:49 -04:00
Gmer4Lfe 9a26478498 git_pull_execute: GitHub fallback when GITEA_REPO_PATH is empty
End users leave GITEA_REPO_PATH="" in master.conf (template default).
Before hitting any Gitea detection logic, the script now checks for this
and does git pull --ff-only origin main directly — origin is already
GitHub since the .plg cloned from there.

Sparse checkout skipped on this path: conf files are gitignored so
nothing sensitive is in the repo to exclude.

Developer path (GITEA_REPO_PATH configured) is completely unchanged.
2026-05-30 16:55:25 -04:00
Gmer4Lfe 5edb32f48d Deployment: gitignore, remove script, version bump to 2026.05.30
.gitignore:
  Excludes Configurations/host*.conf + master.conf (personal credentials)
  and Configurations/*.bak, data/, *.log, *.lock.
  Templates remain tracked. Files stay on disk — only untracked from git.

Plugin/varaverk.plg:
  Version: 2026.05.28 → 2026.05.30
  <CHANGES>: proper changelog entries for both releases covering
    wizard, setup flow, Partnership highlights, HOST2 paths,
    onboard Step 9, pre-onboard graceful state, GitHub links.
  Remove script: stops fallback.sh cleanly (--stop), kills watchdog
    orchestrator, removes cron file + calls update_cron, removes web
    symlink and plugin flash dir. Preserves appdata with clear message.
2026-05-30 16:51:18 -04:00
Gmer4Lfe 7e01f6d3db Differentiate API key missing vs API unreachable in monitor banner
unraid_api.php: track key_missing separately from general fallbacks.
  vv_api_data() sets key_missing=true when HOST*_UNRAID_API_KEY is empty.
  vv_api_get_status() includes key_missing in the status payload.

monitor.php: two distinct banner states instead of one orange warning.
  key_missing → subtle dark/grey note: "API key not configured — add
    HOST1_UNRAID_API_KEY in Scheduler → host conf to enable enhanced monitoring"
  key present but unreachable → existing orange ⚠ with fallback list.
  No banner at all when API is working correctly.
2026-05-30 16:26:51 -04:00
Gmer4Lfe 10fc703e57 Add GitHub link, fix Settings page, direct users to setup on install
Plugin/varaverk.plg:
  - Add support="https://github.com/FailedProxy/Varaverk/issues"
  - Install completion log now says "open Varaverk to complete setup"
    with navigation hint — user lands on wizard automatically

Plugin/unraid/VaraverkSettings.page:
  - Fix stale SCRIPTS_DIR default (unraid_scripts → Varaverk)
  - Add GitHub / Issues / Changelog links at bottom of settings page

Plugin/unraid/Varaverk.page:
  - Small "⎋ GitHub" link right-aligned in the tab bar
    links to github.com/FailedProxy/Varaverk in a new tab
2026-05-30 16:22:54 -04:00
Gmer4Lfe d09ea11694 Onboard Step 9: push master.conf to all listed hosts on completion
After Step 8 (arr bootstrap), owner calls vv_push_master_conf() and
vv_push_setup_state() via php -r. SSH is established at this point so
the probe passes and all listed hosts get the authoritative master.conf
immediately — no manual save required.

Skipped if onboard failed, dry-run mode, or php unavailable (with
fallback instruction). Result shown in onboard summary as Step 9.
2026-05-30 16:14:07 -04:00
Gmer4Lfe 0121462576 Graceful degradation before partnership/SSH is set up
Fix 1 — Monitor partner card (common.php + monitor.php):
  vv_remote_hosts_stats() no longer skips hosts with no API key.
  Returns no_api_key:true entry instead. Monitor JS renders
  "API key not configured — complete Onboard to enable" instead
  of a blank space.

Fix 2 — rawconf push not alarming pre-onboard (config.php + scheduler.php):
  Probe failures (Tailscale not found, plugin not installed) now carry
  ready:false. JS treats ready:false results silently — button shows
  "✓ Saved" not "push failed: HOST2" before SSH is set up.
  Only genuine post-onboard failures (ready not false) show as errors.

Fix 3 — Partnership Onboard button (partnership.php):
  Disabled with tooltip when no partner hostname is in master.conf.
  When partner configured but not onboarded, adds explanation note:
  "Onboard will generate your SSH key, exchange it with the partner..."
  No partner configured: "Edit master.conf and set HOST2."
2026-05-30 16:01:44 -04:00
Gmer4Lfe 974e3cf2cf Setup: all hosts land on Partnership after conf setup, not just HOST1 2026-05-30 15:53:52 -04:00
Gmer4Lfe 64f2c89a40 Setup mode: HOST1 lands on Partnership with Onboard highlighted
scheduler.php: after host1.conf save in setup mode, redirect to
  ?tab=partnership&vv_onboard=1 instead of Monitor.
  HOST2+ still redirects to Monitor (they don't manage the partnership).

partnership.php: detects vv_onboard=1 URL param after actions render.
  Adds pulse animation + box-shadow to the Onboard button and scrolls
  it into view. One-shot — gone when user navigates away.
2026-05-30 15:52:41 -04:00
Gmer4Lfe af89258bbd Setup wizard: full first-run flow for HOST1 and HOST2
Varaverk.page: also shows wizard when local host.conf is missing
  (handles master.conf pushed by HOST1 before HOST2 installs plugin).

pages/setup.php: three wizard flows
  - Standard: blank master.conf, fill hostnames, redirect to scheduler
  - Host2/state file: state file detected, pull master.conf from HOST1 via SSH
  - Conf-only: master.conf already filled (was pushed), just create local host.conf

api/setup.php:
  - save action: writes master.conf + host.conf, creates varaverk_setup.db state file,
    redirects to ?tab=scheduler&vv_setup=master.conf
  - pull action: resolves HOST1 Tailscale IP, queries HOST1 SCRIPTS_DIR, SCPs
    master.conf, creates local host.conf, redirects to ?tab=scheduler&vv_setup=hostN.conf

include/config.php: vv_setup_state_read/write/push helpers.
  vv_push_setup_state() pushes varaverk_setup.db to /boot/config/ on all known
  remotes — no plugin-readiness probe needed (flash is always accessible).

api/rawconf.php: calls vv_push_setup_state() alongside master.conf push.

pages/scheduler.php: setup mode via ?vv_setup=<conf> URL param.
  Auto-opens the specified conf file on page load (DOMContentLoaded).
  vvSaveRawConf: in setup mode, skips confirm dialog and forces sequence:
    master.conf save → auto-open hostN.conf
    hostN.conf save → redirect to Monitor (setup complete)
2026-05-30 15:43:04 -04:00
Gmer4Lfe 1e9681a71e Add first-run wizard, host.conf template, fix GitHub URL
Plugin/varaverk.plg: URL updated to github.com/FailedProxy/Varaverk

Configurations/host.conf.template:
  Full host conf structure with HOSTN/hostn placeholders.
  All personal values blank, all sections documented.
  Covers identity, rsync, docker, fallback, media, monitors,
  transcodes, arrs, system watchdog, resource manager.

Varaverk.page: checks if HOST1 is blank before rendering tabs.
  If blank → shows setup wizard, returns early (tabs never render).

pages/setup.php: first-run wizard UI.
  Auto-populates hostname from hostname -s.
  Role selection: primary (HOST1) or partner (HOST2+).
  Partner slot selector for HOST3+.

api/setup.php: handles wizard form POST.
  Writes HOST1/HOST2 (and HOST3+) into master.conf preserving all
  other content. Creates host*.conf from template with HOSTN/hostn
  replaced and SSH key path pre-filled from hostname convention.
  Never overwrites an existing host*.conf.
2026-05-30 15:22:46 -04:00
Gmer4Lfe 6549ed0301 Add .plg install script and master.conf.template
Plugin/varaverk.plg:
- Method="install update": git clone (fresh) or pull (update)
  Validates Unraid, checks array is started via shfs mount, clones
  to SCRIPTS_DIR (read from varaverk.cfg, default /mnt/user/appdata/Varaverk),
  creates Plugin/unraid symlink, inits varaverk.cfg, bootstraps master.conf
  from template on first install.
- Every boot: lightweight boot.sh recreates symlink if missing (no git ops).
- Method="remove": removes web symlink, leaves appdata intact.

Configurations/master.conf.template:
- Full master.conf with personal values blanked: HOST1/HOST2 empty,
  GITEA_REPO_PATH empty, personal container names in profiles cleared,
  FALLBACK_ENABLED=false, CRITICAL/DAILY rsync defaults corrected to true.
  New users fill in HOST1, HOST2, then proceed to partnership setup.
2026-05-30 15:15:40 -04:00
Gmer4Lfe 5ebf1fc96f Add failsafes to vv_push_master_conf before SCPing
Single SSH probe per remote checks all three conditions in one call:
- plugin cfg exists (varaverk.cfg present with SCRIPTS_DIR)
- Configurations/ dir exists at that path
- master.conf already present on remote

Any failure skips that host entirely rather than pushing blind.
Uses the discovered SCRIPTS_DIR as the SCP destination, not ours.
2026-05-30 14:43:37 -04:00
Gmer4Lfe b5d7413d88 Query remote SCRIPTS_DIR before SCPing master.conf
Instead of assuming the remote uses the same appdata path as the local
host, SSH-grep their varaverk.cfg first and SCP to their actual
Configurations/ dir. Falls back to /mnt/user/appdata/Varaverk if the
plugin isn't installed or the file can't be read.
2026-05-30 14:37:47 -04:00
Gmer4Lfe da0c303f22 Push master.conf to all partners immediately on raw-editor save
vv_push_master_conf() in config.php: finds all remote HOST* entries,
resolves Tailscale IPs, SCPs master.conf to each.
rawconf.php calls it after a successful write when file=master.conf.
Scheduler save button shows sync status: "✓ Saved · synced to HOST2"
or "✓ Saved · push failed: HOST2" on error.

Also fix path bug in partnership_transfer.sh — was SCPing to
appdata root instead of Configurations/.
2026-05-30 14:21:02 -04:00
Gmer4Lfe 26f3778786 Remove redundant Scripts dir field from Scheduler tab
VaraverkSettings.page (Settings → Other Settings) now owns SCRIPTS_DIR.
The inline Advanced-mode field and vvSaveSettings() in the Scheduler tab
were a second path to the same write — removed.
2026-05-30 14:06:28 -04:00
gmer4lfe e6a0ab8e64 conf: add FALLBACK_PARTNERSHIP gate vars, remove PLAY_SYNC section 2026-05-30 10:24:56 -04:00
Gmer4Lfe 0fe99cf2a9 rename: appdata/varaverk → appdata/Varaverk (capital V throughout) 2026-05-30 10:22:51 -04:00
Gmer4Lfe 2d5a084d2b fix: GITEA_REPO_PATH = FailedProxy/Varaverk.git 2026-05-30 10:21:26 -04:00
Gmer4Lfe afe5c10679 fix: GITEA_REPO_PATH org — FailedProxy/varaverk not Varaverk/varaverk 2026-05-30 10:18:36 -04:00
Gmer4Lfe 921900b23b rename appdata folder and repo from unraid_scripts to varaverk
- TARGET_DIR, DATA_DIR: /mnt/user/appdata/unraid_scripts → /mnt/user/appdata/varaverk
- GITEA_REPO_PATH: Varaverk/Unraid_Scripts.git → Varaverk/varaverk.git
- DEV_ROOT: .../Development/Unraid_Scripts → .../Development/varaverk
- deploy hook path updated in .claude/settings.json
- All script comments, docs, and manual paths updated throughout
2026-05-30 10:07:03 -04:00
Gmer4Lfe 788c04ce9d play_state_sync: sync across all hosts via Tailscale
Discover all HOST*_TRANSCODE_SERVERS from every configured host.
For remote hosts, rewrite localhost/127.0.0.1 in the URL to their
Tailscale IP (via resolve_tailscale_ip). Unreachable hosts are
warned and skipped — partial sync continues for reachable servers.

Adding a new host needs no script changes — just HOST*_TRANSCODE_SERVERS
in the new host conf.
2026-05-30 00:23:32 -04:00
Gmer4Lfe 1184be3e28 play_state_sync: move to CRITICAL_MAINTENANCE_SCRIPTS (every 30min)
Removed from DAILY_MAINTENANCE_SCRIPTS — critical orch already covers it
at a much tighter cadence. Play state stays in sync within 30 minutes of
any watched/resume activity on either server.
2026-05-30 00:17:54 -04:00
Gmer4Lfe 23062acdac play_state_sync: fix jq combine fallback + detect_hosts; load_config: fix word-split on paths with spaces
play_state_sync.sh:
- Add detect_hosts() call so TRANSCODE_SERVERS alias is populated
- Switch MEDIA_SERVERS → TRANSCODE_SERVERS (correct array name from host*.conf)
- Fix malformed jq fallback in combine step (was {"} now handled with if/else)
- Skip placeholder API keys in _add_server

load_config.sh:
- Replace 'for x in $(ls glob)' with 'while read < <(printf glob | sort)'
  so paths with spaces (e.g. dev workspace) don't get word-split
2026-05-30 00:13:26 -04:00
Gmer4Lfe 26693fd11f Add play_state_sync.sh — sync watched state across Emby + Jellyfin
Syncs played/resume state bidirectionally across all configured Emby
and Jellyfin servers. Newest LastPlayedDate wins; users matched by
name (case-insensitive); unmatched users skipped cleanly.

Matching: IMDb/TMDB for movies, TVDB+s/e for episodes, MusicBrainz
track ID for audio. Also syncs resume positions for partial plays.

Config: PLAY_SYNC_ENABLED, PLAY_SYNC_DAYS (default 90), PLAY_SYNC_TYPES.
Modes: --dry-run, --status, --full (ignore day window), --log.
Wired into DAILY_MAINTENANCE_SCRIPTS after arr cleanup.
2026-05-30 00:02:18 -04:00
Gmer4Lfe ce9748096c Scheduler: extra args input on script rows
- Tools and Custom: args input always visible (translucent at rest, full on hover)
- Orch children: args input hidden when orch is on, shown when orch is off
  (same toggle as the cron field — orch off = standalone mode)
- vvRunJob/vvDryRun: pick up .vv-script-args value, POST as extra_args
- run.php / dryrun.php: accept extra_args, validate against shell metacharacters,
  append to run_job.sh invocation (flows through SCRIPT_ARGS to the script)
- CSS: .vv-script-args — 30% opacity at rest, 100% on hover/focus
2026-05-29 23:56:15 -04:00
Gmer4Lfe d2eb060fe5 docker_prune_images: add --all mode for full orphan cleanup
Default still removes only dangling (untagged) images.
--all removes stopped containers first, then all images not used
by any running container — clears tagged orphan images left behind
by removed or stopped apps.
2026-05-29 23:36:59 -04:00
Gmer4Lfe 86048b32d3 Plugin: common.php library, watchdog expansion, monitor + scheduler improvements
PHP architecture:
- Extract common.php from monitor.php — shared system functions (vv_system_info,
  vv_memory_breakdown, vv_remote_hosts_stats, disk/GPU/UPS/network/docker/parity, etc.)
  now live in one place; monitor.php and watchdog.php both require common.php
- Add unraid_api.php as explicit include (was implicit via config.php chain)
- confform.php: add missing require_once config.php (implicit dep made explicit)
- Delete orphaned pages/docs.php and pages/config.php (absorbed into scheduler)

Watchdog page:
- Add Storage watchdog card (growth + log strikes, baseline age, suppress ceilings)
- Add Network watchdog card (NPM strikes, DDNS domain/container, NPM URL)
- One host per row layout — all 5 watchdog cards equally spaced via inner grid
- Watchdog now uses Unraid API for local system stats; remote nodes with API key
  but no SSH get system info from vv_remote_hosts_stats() with api_only flag
- SSH bundle: /proc/meminfo passed as raw section instead of awk-parsed header
  fields — fixes RAM showing 0 on remote hosts where awk quoting was unreliable
- vv_wd_local_system() rewritten as thin wrapper over vv_system_info() + vv_memory_breakdown()

Monitor page:
- Watchdog card: add stability strikes, storage watchdog strikes, network NPM status,
  live system stats (rootfs/log/tmp %, RAM free, load, CPU temp, zombies, NIC, sshd)
- Row height: switch from max-height on cards to minmax(0, calc(...)) on grid track —
  all cards in a row now fill to the tallest card's height correctly (fixes Pools card
  being shorter than neighbours)

Scheduler page:
- Add Tools section above Custom Scripts — lists Tools/*.sh with run/dry-run/cron/log
- vv_tools_scripts() function in scheduler.php include

Tools:
- Add docker_prune_images.sh — removes dangling Docker images; --dry-run and --status modes
2026-05-29 23:33:52 -04:00
Gmer4Lfe 8f05f0d27c Docker tab: full inspect detail — icon, IP, ports, paths per container
- Replace pill view with per-container rows showing full detail
- docker inspect batch call: networks+IPs, port mappings, bind mounts
- Container icon from template XML, name links to WebUI if configured
- Network IP badges (blue), port mapping badges (yellow)
- Bind mount paths shown src→dst, collapsible expand for >3 paths
- Large folders (>7 containers) auto-span full width
- Status badge: RUNNING/STOPPED/PAUSED/EXITED with colour
- Stopped containers dimmed, icons load from template XMLs
2026-05-28 22:48:06 -04:00
Gmer4Lfe 00a8a64c4e Docker tab: own config file, folder.view3 becomes optional sync target
- Primary store moved to /boot/config/plugins/varaverk/docker_folders.json
- No dependency on folder.view3 plugin being installed
- Auto-imports folder.view3 JSON on first run if it exists (one-time bootstrap)
- Mirrors writes to folder.view3 JSON only if that plugin's directory is present
- Toolbar shows '⇄ folder.view3' badge when sync is active
2026-05-28 22:41:10 -04:00
Gmer4Lfe e95fd30e13 Varaverk: Docker tab — folder management with conf + folder.view3 JSON dual-write
- New Docker tab (between Scheduler and Watchdog)
- Reads /boot/config/plugins/folder.view3/docker.json — fully compatible with folder.view3 plugin
- Writes changes to both docker.json AND HOST*_DOCKER_FOLDER_MAP in host*.conf simultaneously
- Edit mode: rename folders (inline input), delete folders, move containers via popover picker, create new folders
- Drift banner: highlights containers where conf desired state doesn't match json actual state
- Sync conf→JSON: apply conf desired state to json (fixes drift after onboard)
- Sync JSON→conf: capture manual json edits back into conf
- Ungrouped section shows all containers not assigned to any folder
- Onboard scripts can read HOST*_DOCKER_FOLDER_MAP to auto-place new containers
2026-05-28 22:39:44 -04:00
Gmer4Lfe fb051b60c1 Varaverk: FallBack + Watchdog tabs; plugin path restructure to Plugin/unraid/
- FallBack tab: per-node tier inventory + active fallback card with duration, tier, handback strikes, running container status
- Watchdog tab: live system health (RAM bar + thresholds, load, uptime, daemon), docker watchdog strikes + skip list + restart history, stability strikes + reboot log, resource pressure alert card, config inventory (mem limits, required, pause/stop lists)
- Swapped partnership/arrs tab order; FallBack between partnership and watchdog
- Plugin source tree moved from Plugin/usr/local/emhttp/plugins/varaverk/ to Plugin/unraid/
- Deployment/ conf templates added
2026-05-28 22:24:50 -04:00
Gmer4Lfe 446794e41d Varaverk: grid layout tweaks + mobile folder fix
- Move Parity to row 4 (cols 1-2), Scripts to row 2
- GPU card: span 2
- Memory card: proc strip clips with ellipsis instead of overflowing
- Containers & VMs: use JS window.innerWidth check (<=640) for single-column
  folder layout instead of CSS media query — fixes badge alignment on mobile
  where Unraid's viewport doesn't trigger CSS breakpoints reliably
2026-05-26 19:19:22 -04:00
Gmer4Lfe 072c8b720d Varaverk: monitor grid overhaul + Containers & VMs card
Monitor layout (8-col grid):
- Row 1: System | Power | CPU | Memory | Network
- Row 2: Scripts | Partner & Fallback (span 3) | Containers & VMs (span 4)
- Row 3: GPU (span 2) | Transcode (span 2) | Streams (span 4)
- Row 4: Parity (cols 1-2) | Pools (cols 3-4) | Array (cols 5-8)

New Containers & VMs card:
- Reads FolderView3 folders from docker.json; expand/collapse per folder
- VMs listed first (virsh); containers show start/stop/webui/edit actions
- 2-column balanced layout; collapses to 1 column below 900px
- Docker WebUI URLs resolved from dockerMan template XMLs

New files: include/vms.php, include/docker_folders.php, api/docker_action.php, api/snapshot.php
Responsive: explicit grid-column placements reset at 1024px breakpoint
2026-05-26 18:59:19 -04:00
Gmer4Lfe 6078af0dbb Varaverk: arrange mode, folder management, rsync standalone, layout fixes
Scheduler UI:
- Arrange mode: drag scripts between orchs and reorder within arrays; right
  panel shows unassigned script pool; Save Arrangement commits to master.conf
- + Folder: named collapsible subfolders for Custom Scripts stored in schedule.json
- Rsync children: hide Run/Dry Run/Log/location when orch is ON; show standalone
  location + cron controls when orch is OFF; cron only fires when both filled
- Non-conf-managed children (transcode): toggles now show enabled when orch is on
- Right panel height sync: fix ResizeObserver feedback loop via align-self:flex-start
  on left panel and left.offsetHeight in vvFitRight
- How do I use this: updated to cover arrange, folders, rsync standalone, transcode

New API endpoints:
- board.php, clearlock.php, movescript.php, rawconf.php, readscript.php
- reorderarray.php, rsync_standalone.php, savefolders.php

run.php / dryrun.php: accept optional --location= arg for standalone rsync calls
2026-05-25 21:46:12 -04:00
Gmer4Lfe 6b30768853 webgui_watchdog: mark executable 2026-05-24 23:33:39 -04:00
Gmer4Lfe 8e0d68665c Move dangling image prune from docker_update.sh to docker_daily_restart.sh
Restarts create the orphans — prune belongs in the same script immediately
after the restart loop, not in the update script that runs before it.
2026-05-24 23:32:00 -04:00
Gmer4Lfe 83ff9fca5e docker_update: prune dangling images after pull (both normal and remainder modes)
Daily restarts create orphaned images that were never cleaned up.
Added docker image prune -f section matching docker_update_remaining.sh pattern.
Prune runs each cycle so orphans from the previous day's restart are removed daily
rather than waiting for the weekly docker_update_remaining.sh sweep.
2026-05-24 23:14:31 -04:00
Gmer4Lfe 83195ebb9e monthly_maintenance: reschedule to 0 0 15 * * (15th at midnight)
Previously ran daily at 3am with internal self-gating. Now scheduled directly
on the 15th — uptime and interval gates still apply; a skip means next month's 15th.
2026-05-24 23:10:31 -04:00
Gmer4Lfe dfb462a18e Varaverk: suggested cron hints left of every cron input
- vv_script_children() now calls vv_script_suggested_cron() per child,
  adding suggested_cron and suggested_label to each child entry
- Orch rows (non-event) and regular script child rows render a faint
  .vv-cron-hint span to the left of the cron input showing the suggested
  cron from the script's # Schedule: header
- Clicking the hint fills in the cron input (data-cron + onclick)
- Tooltip shows full "suggested_cron — label" string on hover
- .vv-cron-hint: color #444, brightens to #888 on hover
2026-05-24 22:59:33 -04:00
Gmer4Lfe d6cfcaef46 Varaverk: always open Scheduler Information on page load; restore button for last log 2026-05-24 22:51:35 -04:00
Gmer4Lfe eade6072b0 Varaverk: Scheduler Information panel with structured how-it-works sections
- Right panel title: "Suggested Schedules" → "Scheduler Information"
- Removed top hint paragraph; info now lives in the panel itself
- Added three collapsible info sections (open by default) at top of panel:
  Controls — toggle, cron, run, dry run, log, stop, verbose, config
  Orchestrators — enabled/disabled behavior, child cron rules, event triggers
  Children & Advanced — toggle semantics, independent cron, rsync flag badge
- Bullet lists use CSS columns:2 with column-fill:balance for even distribution
- "Suggested Schedules" divider separates info from parsed schedule blocks
- Added vvToggleSug() for DOM-traversal-based accordion (no ID dependency)
2026-05-24 22:47:34 -04:00
Gmer4Lfe cdd2dfc990 Varaverk: rsync flag toggle + stop button
- Rsync/rsync.sh children in Advanced now show as conf_flag type when the
  parent orch controls a *_RSYNC_ENABLED tier flag; toggle writes true/false
  to master.conf instead of comment/uncommenting a SCRIPTS array entry
- Added vv_conf_flag_value() and vv_conf_flag_set() helpers in scheduler.php
- Added api/flag_toggle.php endpoint (validates *_RSYNC_ENABLED pattern)
- Added api/stop.php: kills process group, sweeps stuck locks, updates stat
- vv-flag-badge CSS (amber, monospace) to distinguish from event/script rows
- vvSaveChild() routes conf_flag children to flag_toggle.php unconditionally
- vvApplyOrchState() keeps conf_flag toggle at real flag value; disables when orch off
- vvSaveAll() skips conf_flag children (immediate-save only)
2026-05-24 22:38:33 -04:00
Gmer4Lfe d0d56ed8b9 scheduler: orch-god toggle model — children managed via master.conf
When orch is ON (god mode):
- Children's toggle state is read from master.conf comment status
- Toggling a child comments/uncomments its line in the *_SCRIPTS array
- Child crons are suppressed in vv_cron_rebuild — orch is the sole trigger
- Children not found in any *_SCRIPTS array are shown disabled (read-only)

When orch is OFF:
- All children flip to off; schedule.json updated immediately
- A child with a cron value + enabled toggle gets its own independent cron entry
- A child with no cron does nothing when enabled

New: vv_conf_script_map() — cached per-request scan of master.conf arrays
New: vv_parse_conf_array_full() — includes commented entries (disabled scripts)
New: vv_conf_toggle_script() — comments/uncomments a script line in master.conf
New: api/conf_toggle.php — endpoint for child toggle → master.conf write
2026-05-24 22:24:14 -04:00
Gmer4Lfe 3186097941 scheduler: revert legend grid — restore original hint paragraph 2026-05-24 22:06:48 -04:00
Gmer4Lfe 4832dd8d4e scheduler: replace hint paragraph with compact 3-column legend grid 2026-05-24 21:56:27 -04:00
Gmer4Lfe 655c520ae8 scheduler: add Array Starting / Array Stopping event triggers
Two hardcoded event-triggered entries appear at the top of the scheduler
(array_started.sh / array_stopping.sh). They show an  Array Start /
 Array Stop badge instead of a cron field and are enabled/disabled via
the normal toggle.

Static event scripts fire them via Unraid's event system:
- event/disks_mounted/array_start_jobs  → runs in background (non-blocking)
- event/disks_unmounting/array_stop_jobs → runs foreground (blocks until done)

vv_cron_rebuild() skips @array_* entries so they never land in the cron file.
Scripts executed on each event are managed in master.conf via
ARRAY_START_SCRIPTS and ARRAY_STOP_SCRIPTS arrays.
2026-05-24 21:54:13 -04:00
Gmer4Lfe 1540c62d3a scheduler: smart auto-scroll replaces separate scroll lock checkbox; lidarr: allow single-seed candidates
Auto Scroll now pauses automatically when user scrolls up and resumes
when they reach the bottom — no separate Scroll Lock needed.

Lidarr discovery no longer hard-skips single-seed candidates; they
score low on breadth but can still reach threshold on merit.
2026-05-24 21:40:03 -04:00
Gmer4Lfe 253d5bf2e1 fix(varaverk): remove legacy /etc/cron.d/varaverk on cron rebuild
Before update_cron was wired in, the plugin wrote directly to
/etc/cron.d/varaverk. That file persisted after the migration and
caused duplicate job firing (two watchdog instances at :00/:15/:30/:45).
The second instance hit the lock, exited with warn, and overwrote the
stat file — killing the running indicator while the first was still live.

vv_cron_rebuild() now unlinks the legacy file after every update_cron
call. Since rebuild_cron (boot event) calls vv_cron_rebuild(), the
cleanup runs on every reboot and every schedule save.
2026-05-24 21:27:38 -04:00
Gmer4Lfe bcb1956bbe feat(varaverk): append logs per run with timestamp separator
run_job.sh was overwriting the log on every cron fire, making it
impossible to see run history. Switch to append mode, print a
── YYYY-MM-DD HH:MM:SS ── separator before each run, and trim to
the last 1000 lines after each run to keep logs bounded.
2026-05-24 21:12:28 -04:00
gmer4lfe 7a61a56ee1 fix(common): prepend /usr/local/sbin to PATH for cron compatibility
Cron runs with PATH=/usr/bin:/bin, which omits /usr/local/sbin where
tailscale (and other Unraid tools) live. resolve_remote_ip silently got
empty results from both tailscale calls, failing all 3 retry attempts
every scheduled run. Export the full path at source time so all scripts
find tailscale regardless of how they're invoked.
2026-05-24 21:08:39 -04:00
gmer4lfe fc1fd27a3f fix(common): lock registry prevents EXIT trap overwrite orphaning locks
Scripts calling acquire_lock followed by acquire_rsync_lock (rsync.sh)
or a custom EXIT trap (resource_watchdog.sh) would overwrite the lock
release trap, leaving the first lock file behind on exit.

Replace per-acquire trap with a _LOCK_FILES registry. _register_lock()
appends each lock file to the array and sets a single _release_all_locks
trap. All acquired locks release together on exit regardless of how many
traps are subsequently set or overwritten.

resource_watchdog.sh: chain _release_all_locks into both its custom trap
and the state-persisted disarm path so the lock releases in all exit paths.
2026-05-24 21:02:59 -04:00
Gmer4Lfe 207dead909 monitor: darken transcode stream bar to deep orange (#e65100) 2026-05-24 20:20:42 -04:00
Gmer4Lfe 2128539450 style(monitor): Live TV bar blue, transcode orange, direct green 2026-05-24 20:16:59 -04:00
Gmer4Lfe 0f6154ad82 style(monitor): stream progress bars match parity blue (#1e3a5a) 2026-05-24 20:15:46 -04:00
Gmer4Lfe 0757d07ddf fix(varaverk): move varaverk.plg to /boot/config/plugins/ root (matches all other plugins) 2026-05-24 20:10:21 -04:00
Gmer4Lfe 376c7f7bc8 feat(scheduler): persist invert preference in localStorage 2026-05-24 20:00:00 -04:00
Gmer4Lfe 51fe2664b8 feat(scheduler): scroll lock on by default, persisted in localStorage 2026-05-24 19:58:44 -04:00
gmer4lfe b754842da2 fix(common): retry Tailscale IP resolution up to 3 times before failing
The first cron run of critical_sync_maintenance failed because Tailscale
had a transient moment at startup. resolve_remote_ip() now retries 3 times
with a 5s delay before giving up, making it resilient to brief daemon
hiccups without masking real peer-offline conditions.
2026-05-24 18:56:59 -04:00
Gmer4Lfe 7c14627bc3 feat(scheduler): live running indicators for cron-triggered jobs
Add api/status.php — reads all scheduled jobs' stat files and returns a
{id: status} map. The scheduler page polls it every 3s and lights up the
dot on any job whose stat shows status=running, clearing it when done.

Replace single vvRunningId with vvRunningSet (Set) so multiple jobs can
show as running simultaneously. vvSetDot/vvClearDot handle per-job dots
and the header dot for the active job. Remove stale-count detection from
vvFetchRight — status poll is now the single source of truth.
2026-05-24 18:46:45 -04:00
Gmer4Lfe 6600565dd5 feat(varaverk): add local .plg registration; remove dev-mode cron fallback
Create varaverk.plg on flash (/boot/config/plugins/varaverk/varaverk.plg).
On boot, rebuild_cron copies it to /var/log/plugins/ so update_cron natively
picks up varaverk.cron and merges it into /etc/cron.d/root.

With the .plg in place the dev-mode direct-inject fallback in vv_cron_rebuild()
is no longer needed and has been removed.
2026-05-24 18:38:43 -04:00
Gmer4Lfe 03e72b6a06 fix(scheduler): use Unraid plugin cron mechanism instead of /etc/cron.d/varaverk
dcron uses the filename in /etc/cron.d/ as the username, so a file named
'varaverk' ran jobs as a non-existent user and was silently ignored.

Switch to writing /boot/config/plugins/varaverk/varaverk.cron and calling
update_cron (which merges all plugin .cron files into /etc/cron.d/root).

In dev mode (no varaverk.plg registered), fall back to injecting our entries
directly into the live root crontab via crontab -c /etc/cron.d -.
2026-05-24 18:11:50 -04:00
Gmer4Lfe 57d55c647c varaverk: replace User Scripts dependency with native job tracking
run_job.sh: new wrapper called by scheduler cron for every job.
  Writes /var/log/varaverk/<id>.json (status/start/end/exit/pid)
  and /var/log/varaverk/<id>.log (latest run output, overwritten).
  Maps exit 0→ok, 1→warn, 2+→error so watchdog "took action" runs
  show warn not error.

scheduler: cron now calls bash run_job.sh instead of inline bash -c.
  Added vv_job_stat_path(). LOG_DIR moved to config.php (shared).

monitor: vv_scripts_status() now reads /var/log/varaverk/*.json and
  */*.json — no User Scripts tmpScripts dependency at all.
  Stale running detection via /proc/<pid> check.
  Returns error_count in addition to running/ok/warn counts.

pages/monitor.php: added error pill (red ✗), error icon/color in
  list, duration shown next to age for each script entry.
2026-05-24 17:51:31 -04:00