vv_network_stats() calls vv_conf_vars() and vv_detect_host() which are defined in
config.php. monitor.php had no require for it, causing a PHP fatal error on every
poll → empty JSON → all monitor cards stuck on "Loading...".
Monitor tab:
- CPU card: per-core bars (freq-colored), overall usage bar, rolling history chart
- Memory card: breakdown by system/VM/ZFS/Docker/free with progress bars
- Network card: LAN + ext + Tailscale IP display, live RX/TX chart with auto-scale
- Streams card: Emby/Jellyfin/Plex sessions with playback bar and server badges
- GPU card: adds power draw, encode%, decode% meters
- Transcode card: ramdisk vs SSD location pill, session count, flip history
- Canvas chart helpers: vvDrawChart, vvDrawNetChart, vvMeter, vvFmtBps, vvFmtGib
api/monitor.php: adds cpu, mem, net to response payload
- Add .vv-save-check span to each job row (orchestrators + children)
- CSS: fade-in-then-out animation (visible 1.2s, fades over 2s)
- vvFlashSaved(job): triggers the checkmark animation on a specific row
- vvFlashStatus(el, msg, ok): shows timed status text (was called but missing)
- vvSaveJob: now shows per-job checkmark on successful save
- vvSaveAll: shows checkmark on each job as its response arrives, plus
global "✓ All saved" / "✗ Some failed" status text below the button
Unraid's system crond is dcron (dillon's cron daemon 4.5), which reads
/etc/cron.d/ for system crontabs WITHOUT a username field, and refuses
to execute files that are group- or world-writable.
vv_cron_rebuild() was writing "SCHED root bash ..." (with username field)
and leaving the file world-writable (666), so dcron silently ignored every
entry. Fixed:
- Remove CRON_USER from the generated cron line format
- chmod 0600 the cron file after writing it
- Change suggestion title color from bright green (#6fcf97) to soft grey-blue (#7a9eb5)
- Fix vv_parse_user_script_template() block-detection regex — $ end-anchor
failed on lines ending with multibyte U+2500 ─ chars; removed anchor so
parser now returns all 22 blocks from user_script_plug-in.sh
- Cron and Advanced button vertically aligned in their respective rows
- Verbose checkbox next to Log button — saves immediately, persists to schedule.json
- --log flag injected into cron lines, manual Run, and Dry Run when verbose enabled
- Coffee report rewritten as lean orchestrator over COFFEE_REPORT_SCRIPTS array
- COFFEE_REPORT_SCRIPTS added to master.conf (7 Sunday monitor scripts)
- Scheduler Advanced tab auto-discovers children via existing array detection
Cron input now sits right of the script label in the same row.
Below each row: one-line description pulled live from the script header
(PURPOSE block or first meaningful comment line) — updates whenever
scripts are edited, no plugin changes needed.
Scripts list on left, persistent log panel on right. On screens ≤880px
falls back to stacked single-column. Right panel stays open until page
refresh or another selection. Running dot pulses green on the job row
and in the log header while script executes, clears when log goes stale.
All fetch() POSTs now send application/x-www-form-urlencoded with the
page-injected csrf_token, satisfying unRAID's auto_prepend CSRF check.
All PHP API handlers switched from php://input JSON to $_POST.
Also adds Dry Run button (orange, between Run and Log) that sets
DRY_RUN=1 in the script environment before executing.
- Run button (blue) fires script immediately, opens log panel;
stamps log with manual run timestamp before exec
- Save moved to card footer — one button saves all cron expressions
for the orchestrator and all its children at once
- Toggle still auto-saves immediately on flip (enable/disable is instant)
- Removed onblur from cron inputs — cron only saves on explicit Save
- api/run.php: validates id, appends timestamp, execs script in background
- Per-job log files replace single jobs.log: each script writes to
/var/log/varaverk/<Category>/<script>.log mirroring the job ID
- api/log.php: serves last 200 lines of a job's log file with mtime
timestamp; supports POST ?clear=1 to truncate
- Scheduler page redesigned as full-width cards (one per orchestrator)
with Save + Log buttons; Log toggles an inline panel that polls
every 3 seconds and auto-scrolls — same pattern as unRAID User Scripts
- Children shown under Advanced with identical per-job log panels
- CSS: vv-sched-card, vv-log-panel, vv-log-pre, vv-btn-sm
Non-greedy (.*?) stopped at the first ) found, which could be inside
a comment like '# gracefully stop fallback (not caught by ...)'.
Anchoring the closing paren to start-of-line (^\s*\)) ensures it only
matches the array's actual closing paren, not ) inside comment text.
Orchestrators using dynamic dispatch (array_started, watchdog_orchestrator,
daily/weekly/etc maintenance) iterate \${VARNAME_SCRIPTS[@]} arrays defined
in master.conf. The previous regex only caught static hardcoded paths.
Two-strategy approach, merged and deduped:
1. Static: \$VAR/../Category/script.sh and \$VAR/Category/script.sh patterns
2. Dynamic: detect \${VARNAME[@]} references in the orch, parse that array
from master.conf — handles inline args and skips commented entries
Changes to master.conf arrays are reflected immediately on next page load.
Previous regex only matched literal bash/source calls with bare paths.
Orchestrators use shell variables like \$SCRIPT_DIR/../Transcodes/script.sh
and \$SCRIPTS_ROOT/Category/script.sh — the old pattern missed all of these.
New regex captures the Category/script.sh portion from either pattern,
requires at least one subdirectory (excludes load_config.sh and root-level
utilities), and validates each candidate against the filesystem.
transcode_management now correctly shows transcode_cleanup and transcode_manager.
Orchestrators using master.conf config arrays for dynamic dispatch still show
no children — correct, as those lists cannot be statically parsed.
/etc/cron.d/varaverk is RAM-based and wiped on every reboot. The
disks_mounted event fires early in boot (before Docker) with /boot
already readable, so schedule.json is available to restore the cron
file automatically without any user action.
/var/log/ is RAM-based on unRAID — wiped on reboot. Creating the log
directory in vv_cron_rebuild() ensures it exists before the first cron
job fires, without needing a separate boot script.
- Rename varaverk.page → Varaverk.page: unRAID nginx only routes URLs
starting with a capital letter (~^/[A-Z].*), lowercase caused 404
- Add require_once config.php to include/scheduler.php and include/docs.php:
both used SCRIPTS_DIR constant without including the file that defines it
- Replace hardcoded SCRIPTS_DIR with cfg-file-backed setting: reads from
/boot/config/plugins/varaverk/varaverk.cfg, falls back to default on first run
- Add Plugin Settings card to Config tab with scripts path field
- Add api/settings.php to write the cfg file (validates directory exists)
critical_sync_maintenance.sh runs every 30 minutes (*/30 cron).
Three references in README.md and Partnership/README-Partnership.md
still said 15 minutes from an earlier schedule.
transcode_management.sh runs every 7 minutes. Six references across
README.md, README-Transcoding.md, Manual-Transcoding.md, transcode_manager.sh,
and transcode_cleanup.sh still said 3 minutes from before the schedule change.
If PaddleOCR (or any GPU sidecar) holds all VRAM, --gpus will still
appear to fail even when configured correctly. Added explicit callout:
check nvidia-smi before concluding the GPU flag is wrong.
README-Transcoding now has a dedicated REQUIRED EXTRA PARAMETERS section
with both GPU and non-GPU variants and the Google warning up front.
Manual-Transcoding: two troubleshooting sections that showed mount-only
now show both GPU and non-GPU full strings. NVIDIA section quote style
fixed (--gpus "device=UUID" consistently).
Every search result shows --runtime=nvidia which conflicts with
bind-propagation=shared on unRAID 7.2.5+ and breaks on container
rebuilds. New prominent section explains the correct --gpus approach,
why the old method fails, and the VRAM starvation cascade.
Item #6 in Surprises updated to reference the new section; arr cleanup
renumbered to #8.
Required Mount section now shows full Extra Parameters for both GPU and
non-GPU containers and explains why --gpus beats --runtime=nvidia at
setup time rather than burying it in Troubleshooting.
New troubleshooting entry documents the GPU memory starvation cascade:
OCR sidecar (PaddleOCR) holds VRAM → Jellyfin hard-fails, Emby falls
back to CPU silently. Emby's NVIDIA startup probe is one-shot — VRAM
must be free before restarting or NVIDIA stays disabled for the session.
Includes correct recovery sequence and Tesseract fallback for EmbyCredits.
README callout updated from two to three non-obvious requirements.
Documents the known issue where an unclean shutdown leaves the --mount
bind-propagation entry in a broken state that prevents Emby from starting.
Recovery: remove mount → start → wait for load → re-add mount → restart.
Follows the same extraction pattern as partnership_offboard.sh.
partnership_manager.sh --transfer now exec-forwards to the new script.
Legacy inline block preserved under `if false` for reference.
Fixes in partnership_transfer.sh vs the original inline code:
- WebUI reconfiguration corrected: SSH to new owner (mirror) to set localhost;
reconfigure_local_webuis() on current server to point to new owner IP
- master.conf remote update uses scp push instead of self-SSH with wrong path
- SSH key uses $SSH_KEY directly (was using undefined {HOST*}_SSH_KEY expansion)
partnership_manager.sh:
- fix auto-offboard threshold: × 96 → × 48 (was triggering at 2× configured days)
- fix do_final_sync(): use CRITICAL_SYNC_SHARES if configured; fall back to hardcoded paths
- replace inline --check offboard blocks with background partnership_offboard.sh calls:
• owner path was missing remote container cleanup (steps 8+9) and blocklist
• mirror path was missing blocklist, SSH revocation, CRITICAL_RSYNC_ENABLED=false
• local grace_seconds outside a function (bash error) eliminated with the block removal
• 6hr Tailscale grace sleep was blocking the cron for the full grace window
partnership_offboard.sh:
- reorder owner path: state write moved from step 5 to step 10 (last) so re-running
after a mid-offboard crash restarts from scratch instead of exiting as INACTIVE;
state is now written before the Tailscale grace sleep so --check stops re-triggering
- add FolderView3 remote folder cleanup in step 7 (mirror's fallback folder persisted)
- track step 1+2 outcome with STEP_STOP_OK / STEP_SYNC_OK; summary now reflects actual
result instead of hardcoding ✅ regardless of dry-run or failure
- update header step list to match new step order
master.conf:
- reorder ORCHESTRATORS section by run frequency; add missing entries
- remove heartbeat vars (watchdogs no longer run in continuous cycle)
- remove dead REMOTE_DOCKER_RETRY_WAIT and display-only watchdog interval vars
- move INTERMEDIATE_RSYNC_ENABLED into RSYNC two-tier block; reorder by frequency
common.sh:
- add missing info() and success() definitions — both were called throughout but never defined
- update output tier description to list all 5 functions
- fix double-icon in check_local_disk_temps() error/warn calls
- fix smashed curl/ssh command lines in notify_emby_scan() and check_remote_docker_daemon()
- update check_rsync_enabled() comment to include INTERMEDIATE, ordered by frequency
emby_to_radarr_sync.sh / emby_to_sonarr_sync.sh:
- wire up RADARR_EMBY_LIBRARIES / SONARR_EMBY_LIBRARIES; empty array now scans all libraries
appdata-Failover → appdata-Fallback:
All .md files updated — scripts and confs already used appdata-Fallback.
Share was renamed; docs were the only stale references.
critical_sync_maintenance.sh: */15 → */30, 96/day → 48/day:
critical_sync_maintenance.sh header, master.conf, host1/2.conf comments,
Orchestrators README, User Script Plug-in README, Partnership README/manual/script,
Docker_Essentials README/downloaders_reset.sh, Fallback README,
weekly_sync_maintenance.sh, user_script_plug-in.sh all updated.
rsync_emby_failover User Script superseded:
Emby dirty sync was already in HOST1_CRITICAL_SYNC_SHARES — it now runs inside
critical_sync_maintenance.sh every 30min alongside auth sync and partnership check.
Section in User Script Plug-in README marked for deletion from plugin.
transcode_management.sh: */3 → */7:
transcode_management.sh, transcode_manager.sh, transcode_cleanup.sh headers,
Transcodes README/manual, Orchestrators README, User Script Plug-in README,
user_script_plug-in.sh all updated.
Update the Three-Tier Response and RAM Tiers sections to reflect the
resource_watchdog/stability_watchdog split: MEM_WARN_GB/MEM_SHUTDOWN_GB/
MEM_RECOVER_GB moved to RW_RAM_SOFT/MEDIUM/HARD/RECOVER_GB in resource_watchdog;
stability_watchdog now only holds SYS_WATCHDOG_MEM_GB (reboot trigger). Update
required containers reference from SYS_WATCHDOG_REQUIRED_CONTAINERS (removed)
to HOST*_WATCHDOG_REQUIRED_CONTAINERS in host*.conf.