Commit Graph
719 Commits
Author SHA1 Message Date
Gmer4Lfe 855bc53623 Untrack Configurations/master.conf
Contains live credentials; was tracked despite being gitignored.
Pre-work for the GitHub mirror fallback in git_pull_execute.sh.
2026-07-11 17:03:38 -04:00
Gmer4Lfe 7fa0adbda4 Fix external-link warning on the Partnership tab's web terminal link
Same root cause as the tab-navigation fix (a6fe820): the "Open Terminal"
link builds its href from window.location.hostname (the same server the
plugin is already running on) but Unraid's global external-link guard
still flags it, since it's a fully-qualified URL the guard hasn't seen
allowed before. Added class="localURL", the same escape hatch used for
the tab bar and dynamix's own pages.
2026-07-05 00:00:16 -04:00
Gmer4Lfe 084220692f Add unambiguous prefix-match fallback for NetBIOS-truncated hostnames
Unraid truncates the Server Name to 15 chars. Depending on which form
ends up in master.conf's HOST* value (the truncated OS hostname, or a
longer name matching what Tailscale independently registered for that
peer), either host-identity detection or Tailscale IP resolution could
fail — hit live on HOST2 in both directions this session.

- common.sh detect_hosts(): was case-sensitive exact match only, with no
  fallback and an exit 1 on failure — meaning every orchestrator/watchdog/
  rsync script would hard-fail on a truncated-hostname host, not just the
  web UI. Now case-insensitive, with a prefix-match fallback when the
  local hostname is exactly 15 chars.
- common.sh resolve_tailscale_ip(): already did a bare regex prefix match
  with zero ambiguity handling (pre-existing risk: e.g. server1/server10
  could collide). Replaced with an explicit unambiguous-only check.
- config.php vv_detect_host() / vv_resolve_tailscale_ip(): same treatment,
  kept as close a mirror of the bash logic as PHP allows.

All fallbacks require an EXACT prefix match (never fuzzy/percentage
similarity — considered and rejected, since names like server1/server2/
server3 would be dangerously similar under any generic similarity metric)
and require exactly one candidate to qualify; ambiguous matches are
treated as no match rather than guessed. Verified live against HOST1/
HOST2 in both master.conf configurations (short and long HOST2 value).
2026-07-04 23:49:44 -04:00
Gmer4Lfe abfbaa7f47 Fix host identity detection for NetBIOS-truncated hostnames
Unraid truncates the Server Name to 15 chars (NetBIOS limit). HOST2's
real hostname is "unRAID-Jayred36" but master.conf's HOST2 (matching
what Tailscale shows for this peer, since resolve_tailscale_ip() keys
off the same value) is the untruncated "unRAID-Jayred365" — confirmed
live, Tailscale's own Self.HostName on that machine is truncated too.

vv_detect_host() did a strict case-insensitive match against the bare
`hostname -s` output with no tolerance for this, so it always returned
'unknown' on HOST2. That silently broke the first-run wizard (Varaverk.page
explicitly excludes 'unknown' from the "needs setup" check) even though
host2.conf never existed, plus vv_partner_state() and vv_fallback_active()
in monitor.php which independently reimplemented the same hostname
comparison instead of calling vv_detect_host().

Fix: vv_detect_host() falls back to a prefix match when the local hostname
is exactly 15 chars; vv_partner_state()/vv_fallback_active() now call
vv_detect_host() instead of duplicating the comparison. Verified live on
HOST2 — vv_detect_host() now returns 'host2', partner state correctly
flags HOST2 as is_me, and the wizard-trigger condition now evaluates true.
2026-07-04 23:28:54 -04:00
Gmer4Lfe 3d7b15d6bb Fix vv_push_master_conf() — remote command was expanding locally, not on the remote host
The readiness probe wrapped the remote command in raw double quotes with
manually backslash-escaped inner quotes. shell_exec() runs its command
through an extra local `sh -c` layer beyond the ssh invocation itself, and
because the remote command was double-quoted (not single-quoted/opaque),
that extra local layer expanded the $(...)/${...} substitutions using
HOST1's own environment before ssh ever sent anything to the remote host.
Confirmed live: the exact same command run directly (one shell layer)
returned the correct remote SCRIPTS_DIR; run through an extra sh -c layer
(matching shell_exec's real behavior) it silently evaluated everything
against HOST1's local varaverk.cfg instead, producing an empty probe result
every time — so every push silently reported "plugin not installed" even
though HOST2 was fully installed and reachable.

Fix: build the remote command as a plain string and escapeshellarg() it as
a whole, same pattern vv_pt_ssh() already used safely elsewhere. Verified
live — probe now returns HOST2's real SCRIPTS_DIR and the master.conf push
lands with a matching checksum on both hosts.
2026-07-04 23:19:42 -04:00
Gmer4Lfe 223d5ebfc9 Fix GITEA_DOMAIN value — was set with an https:// scheme prefix
git_pull_execute.sh, varaverk.plg, and gitea_ssh_setup.sh all treat
GITEA_DOMAIN as a bare hostname (gitea_ssh_setup.sh even builds its own
https:// API URL from it). The live value on HOST1 had the scheme
included, which would build a malformed SSH URL
(ssh://git@https://git.gmer4lfe.com:221/...) — hadn't been hit yet since
HOST2's install succeeded via Tailscale peer detection before ever
reaching this fallback tier.
2026-07-04 23:10:05 -04:00
Gmer4Lfe a6fe820a61 Fix external-link warning on tab navigation
Tab links use relative query-string hrefs (?tab=scheduler), which fail
every check in Unraid's global external-link click-guard (BodyInlineJS.php):
not a valid absolute URL, doesn't start with "/", doesn't match a
registered plugin page basename. Confirmed live — the guard's dom.hostname
ends up undefined for these, matching the reported "Always Allow undefined"
dialog text exactly.

Fix: add class="localURL", the same escape hatch dynamix's own pages
(ManagementAccess.page) use for this exact situation. Applied to the main
tab bar and the setup wizard's checklist action links (?tab=partnership).
2026-07-04 23:05:47 -04:00
Gmer4Lfe 7e4db7b504 Fix stale plugin docs and dead links
- unraid_api.php comment still told you to run Deployment/deploy.sh,
  deleted a while back
- VaraverkSettings.page linked to a CHANGELOG.md that doesn't exist
  anywhere in the repo
- Manual-Plugin.md / README-Plugin.md described manually heredoc-ing the
  .plg locally and a .txz-based install that isn't wired up — rewritten
  to describe the actual install flow (raw .plg URL via Plugins ->
  Install Plugin), with plugin_setup.sh's dev-symlink role called out
  separately from that install path
2026-07-04 23:00:57 -04:00
Gmer4Lfe f7fa75fdfb Fix dead/incorrect vars in Plugin/ found during full codebase audit
- WEBGUI_PHP_WAIT was referenced by webgui_watchdog.sh but never defined
  in master.conf, always silently falling back to a hardcoded default
- arrs.php/confform.php still pointed at Media/ for arr cleanup/discovery
  scripts moved to Arrs_Stack/ in b4bc926 — broke the Arrs page's stats
  and the per-script settings editor for those scripts
- docker_folders.php read directly from the optional folder.view3 plugin's
  file instead of Varaverk's own docker_folders.json (the primary store
  since the Docker tab got its own config) — left the Monitor page's
  Docker Folders widget empty on any host without folder.view3 installed
- vv_wd_remote_data() read remote watchdog state files from hardcoded
  /tmp or /boot/config paths instead of the remote's actual STATE_DIR
  (which resolves dynamically and can differ under flash mode) — remote
  node's Watchdog panel was always empty; same wrong path also used for
  two local reads (system_watchdog_oom.db, watchdog_appdata_growth.db)
- rsync.php referenced a {HOST}_MONTHLY_SYNC_SHARES conf var that never
  existed (monthly_maintenance.sh has no rsync section) — nulled out to
  match the existing pattern used for the fallback window
- vv_arr_node_names() did a pointless identity array_map
- vv_dk_webui() had its own duplicate local-IP resolution instead of
  using vv_local_ip(), despite config.php's comment claiming that exact
  duplication was already consolidated
2026-07-04 23:00:26 -04:00
Gmer4Lfe 0581c7b2f4 Fix Gitea SSH probe still failing after info-arg fix — stderr was discarded
Gitea's SSH rejection banner (what the grep matches on) is written to
stderr, but the probe piped stdout only via 2>/dev/null — so the grep
never saw it, on any peer, even after dropping the bogus 'info' arg in
be6c16d. Confirmed live on HOST2: the exact probe command against HOST1's
Gitea prints the banner correctly with 2>&1, empty with 2>/dev/null.

Also corrects the CHANGES entry, which claimed a .txz-based install that
was never wired up — actual distribution is git-clone + symlink, not
packaged.
2026-07-04 22:53:41 -04:00
Gmer4Lfe be6c16d74c Fix Gitea SSH probe in plugin installer — drop bogus 'info' command
The probe ran 'ssh git@$ip info' expecting Gitea's banner in the response,
but 'info' is a Gitolite convention Gitea doesn't implement — it returns
'error: Too few arguments' instead, which never matched the grep, so a
real reachable Gitea host was never detected. Confirmed on HOST2: connecting
with no trailing command returns Gitea's actual banner correctly.
2026-07-04 01:03:29 -04:00
Gmer4Lfe c2597cb516 Fix Tailscale peer discovery in plugin installer — drop python3 dependency
python3 isn't installed on stock Unraid (confirmed absent on HOST1), so the
JSON-parsing pipeline silently produced zero peers every time, making the
Tailscale fallback tier a permanent no-op since it was written. Replaced with
plain 'tailscale status' + awk, matching the pattern common.sh already uses.
2026-07-04 00:39:58 -04:00
Gmer4Lfe 997f9d9117 Add GITEA_DOMAIN fallback tier to plugin installer
Local container and Tailscale peer probe both failing (as happened on HOST2)
left GitHub as the only fallback, which requires the repo to be public. Adds
a domain-based Gitea path in between, matching git_pull_execute.sh.
2026-07-04 00:28:50 -04:00
Gmer4Lfe 6623d1e776 Fix dead/incorrect vars and consolidate duplicated logic into common.sh
Codebase-wide audit pass: fixed real bugs (SSH hangs missing BatchMode,
local-outside-function no-ops, variable name collisions, a truncated
ratio calc, wrong state-dir path, DARK vs NO_INTERNET drift, and more),
then pulled logic that was duplicated across multiple scripts — arr
cleanup safety gates, docker restart ordering, container maintenance
stop/restart, watchdog state-file helpers, partnership role resolution,
cert expiry checks, remote node discovery, and TMDB discovery scoring —
into common.sh so each now has a single implementation.
2026-07-03 23:52:33 -04:00
Gmer4Lfe ef3980cf07 Stop tracking Notes_To-Do.md — personal scratch notes, dev-only
Keeps the file locally for day-to-day use but out of the shared repo.
2026-07-03 23:52:12 -04:00
Gmer4Lfe 260f0a61ce Wire up unused config vars found in follow-up audit pass
TRANSCODE_LOG_RETENTION was documented as trimming the daily transcode log
but never referenced — log grew unbounded. TRANSCODE_ORPHAN_AGE was shown in
--status but never used, so empty session folders were deleted immediately
instead of after the documented grace period, risking a race against ffmpeg
creating a folder just before writing its first segment.

docker_watchdog.sh's daemon-health thresholds were only hardcoded fallbacks
despite comments claiming they were master.conf-configurable, and it
referenced a heartbeat feature that was never implemented (that's owned by
watchdog_orchestrator.sh, its caller) — added the three thresholds to
master.conf for real and removed the stale heartbeat claim.

Also added the missing HOSTN_PARTNERSHIP_SERVICES_STACK block to
host.conf.template (containers.sh already read it via detect_hosts, just
never had a template entry) and corrected play_state_sync.sh's doc comment
for PLAY_SYNC_TYPES' actual default.
2026-07-03 17:45:20 -04:00
Gmer4Lfe 69189bbf18 Fix dead-variable and exit-code bugs found in codebase-wide audit
Same audit as the orchestrator standardization pass (2a062e5), extended to
every remaining script. Found the same class of bug independently recurring:
ramdisk_stop.sh checked $LOG (nothing assigns it, should be $ENABLE_LOGGING),
partnership_onboard.sh checked $LOG_MODE (same issue), emby_session_report.sh
checked $TRANSCODE_PCT which was never computed so the high-transcode alert
could never fire, and storage_migrate.sh never called detect_hosts() so
$MY_ID was empty, silently breaking the post-migration host*.conf update.
partnership_manager.sh used `local` at top-level script scope (invalid outside
a function) and had two master.conf path references missing "Configurations/".

Along the way: several scripts (share_setup.sh, conf_sync.sh,
downloaders_reset.sh, transcode_cleanup.sh, transcode_manager.sh,
remote_arr_cache_writer.sh, upgrade_webhook_handler.sh) had no explicit
trailing exit code, so they always reported success regardless of real
failures. play_state_sync.sh was missing the partnership gate its own header
documented, so remote play-state sync ran even with PARTNERSHIP_ENABLED=false;
it also always exited 0 on sync errors. arr_profile_enforcer.sh and
webhook_setup.sh hand-rolled their own flag parsing instead of common.sh's
parse_args, so --log silently did nothing on either.

system_watchdog.sh was itself an un-standardized mini-orchestrator — converted
to the shared run_orch_child()/JOB_PASS/JOB_FAIL pattern, added the missing
failure notification, and fixed dry-run to pass --dry-run down to children
instead of skipping them outright. Also fixed a stale webgui_watchdog.sh path
in master.conf.template that would break system_watchdog.sh on any fresh
install.

Closed a sibling-drift gap: radarr_cleanup.sh and sonarr_cleanup.sh were
missing lidarr_cleanup.sh's tracked-count percentage-drop safety gate and its
"not configured on this host, skip cleanly" guard — both now match Lidarr's
7-gate model.
2026-07-03 17:35:30 -04:00
Gmer4Lfe eb8c6bb1be Add follow-up notes; fix README wording; drop stale User Scripts readme 2026-07-03 11:01:08 -04:00
Gmer4Lfe 2a062e5140 Standardize orchestrator child-script execution and logging
Every orchestrator invoked its children differently — four near-duplicate
run_job() copies, a differently-shaped run_watchdog(), or plain inline bash
calls, each with its own take on path resolution, pass/fail naming, and
dry-run threading. Extracted one shared run_orch_child() into common.sh so
there's a single place to fix or extend this behavior going forward.

Along the way: watchdog_orchestrator.sh and monthly_maintenance.sh were
checking $VERBOSE, a variable nothing in the codebase ever assigns, so --log
silently did nothing beyond basic logging on those two. Fixed to
$ENABLE_LOGGING. watchdog_orchestrator.sh and array_started.sh had no
trailing exit, so their exit codes reflected whatever the last command
happened to return rather than actual success/failure. transcode_management.sh
had no failure notification and no summary at all. Also made
transcode_management.sh's two-script pipeline config-driven
(TRANSCODE_MANAGEMENT_SCRIPTS in master.conf) instead of hardcoded, for room
to extend it later without editing the orchestrator itself.
2026-07-03 10:57:52 -04:00
Gmer4Lfe 6fd22ae4ee Move Custom Scripts out of the repo and add an Import Script picker
Custom Scripts (the Scheduler page's inline editor) used to save into the
git-tracked Custom/ folder, so anything saved there would end up on GitHub.
They now live in /boot/config/plugins/user.scripts/Varaverk/Scripts, same
folder family as Unraid's own User Scripts plugin. Import Script lets you
browse the whole server and move an existing script in instead of only
creating new ones inline — always a move, never a copy, so no stray
duplicate is left where it came from.
2026-07-03 10:57:35 -04:00
Gmer4Lfe 93aa134aaa Drop claude_startup from ARRAY_START_SCRIPTS — Claude persistence is standalone now 2026-07-03 08:25:39 -04:00
Gmer4Lfe 14ecf0c08a Scrub remaining Claude references from docs 2026-07-03 08:25:09 -04:00
Gmer4Lfe 5d5b60a8ed Remove Claude tooling from repo — personal setup moved to standalone /boot/config/claude_startup.sh 2026-07-03 08:23:28 -04:00
Gmer4Lfe 5d32f58f5d fix boot device detection failing on ZFS /boot
findmnt returns 'flash/boot' for a ZFS dataset, not a /dev/* path.
lsblk -no pkname then fails, leaving transport as 'unknown'. Resolve
ZFS pools to a backing device via zpool before checking transport.
2026-06-27 23:18:36 -04:00
Gmer4Lfe b314aa4aff fix monitor disk used space underreported for spun-down disks
Unraid API returns fsUsed=0 when a disk's filesystem is unmounted (spun
down). disks.ini keeps the last-known value in KB even after spindown —
use it as fallback when isSpinning=false and fsUsed=0. Also remove the
mounted-only guard in the ini fallback path (vv_disk_entry) for the same
reason. Stale comments in user_script_plug-in.sh and partnership_manager.sh
also cleaned up.
2026-06-27 23:08:51 -04:00
Gmer4Lfe 75f2a4e3fd docker_watchdog: skip required containers stopped cleanly or explicitly paused
Exit code 0 on a required container (docker stop, UI stop) now reads as
intentional — no strike, no restart. Non-zero exits still trigger the
existing strike → restart path.

Adds --pause / --resume management commands and a persistent intentional-
stops state file for maintenance windows where even the exit-code heuristic
isn't enough. Containers auto-cleared from the list when seen running again.
2026-06-27 19:00:59 -04:00
Gmer4Lfe cf180c1179 Split Media/ docs into Media/ and Arrs_Stack/ to match folder reorganization
Media README and Manual now cover only the 3 remaining scripts (permissions, cleaner,
play_state_sync). Arrs_Stack README and Manual cover all arr stack scripts including
lidarr_release_fixer. Fixed stale --skip-strike-list reference in flag docs.
2026-06-27 18:49:12 -04:00
Gmer4Lfe b4bc9267e9 Move arr stack scripts from Media/ to Arrs_Stack/
Media/ now holds only media-level scripts (cleaner, permissions, play_state_sync).
All arr management scripts (cleanup, discovery, sync, webhooks, release fixer) live in Arrs_Stack/.
2026-06-27 18:39:33 -04:00
Gmer4Lfe 99b2d1879b Rename --skip-strike-list to --skip-age-check in sonarr/radarr cleanup — same stale naming as lidarr 2026-06-27 18:25:27 -04:00
Gmer4Lfe aa8698ddff Rename --skip-strike-list to --skip-age-check — strike system was removed, flag name was stale 2026-06-27 18:23:57 -04:00
Gmer4Lfe 76c0623190 Align lidarr_release_fixer.sh header with sibling script standard 2026-06-27 18:08:46 -04:00
Gmer4Lfe eb64e52815 Add lidarr_release_fixer.sh — daily fix for wrong MusicBrainz release editions
Reads MUSICBRAINZ_ALBUMID from FLAC (vorbis block type 4) and MP3 (ID3v2 TXXX)
files, matches against Lidarr's known releases, switches monitored=true to the
correct one, and queues RefreshArtist. Runs before lidarr_cleanup.sh in the
daily job list so the strike system doesn't act on files that just needed a
release correction.
2026-06-27 18:06:22 -04:00
Gmer4Lfe 26fb409da5 Fix Emby 4.9 API breakage in session report — update activity types and Items UserId requirement; fix local outside function in cert_monitor 2026-06-27 14:04:53 -04:00
Gmer4Lfe 2d76d10c9d docker_watchdog: skip crash-loop flag for containers that exit cleanly (exit code 0) 2026-06-27 13:48:08 -04:00
Gmer4Lfe 0401d872e4 Script audit: fix stale names, header mismatches, HOST1-hardcoded path maps in lidarr scripts 2026-06-27 13:42:06 -04:00
Gmer4Lfe c9a0ad187b Fix editor horizontal click offset — force inline fontFamily to override Unraid SPA clear-sans 2026-06-27 13:20:03 -04:00
Gmer4Lfe 0aa5851549 Fix editor line-height mismatch caused by Unraid SPA CSS override
Unraid 7's React CSS overrides line-height: 1.5 on textareas to normal.
vvRestoreEditorPrefs() only called vvFontSize() for non-default sizes, so
the inline style that overrides Unraid's CSS was never set for the default
12px case — leaving Firefox to render at ~14px while our code calculated
positions at 18px, putting the cursor 2-3 lines above where clicked.
Now always calls vvFontSize() so the inline lineHeight is always forced.
2026-06-27 13:05:31 -04:00
Gmer4Lfe ef7bc127b6 Fix platform_is_service_enabled to match Unraid's actual cfg format
Unraid quotes values (DOCKER_ENABLED="yes") and uses SERVICE="enable" for
libvirt — the old patterns matched nothing, so docker_watchdog always skipped.
2026-06-27 12:34:12 -04:00
Gmer4Lfe d8e3732f8d Fix Emby auth header and arr cleanup pre-flight scan
Emby 4.9.5 rejects X-Api-Key — notify_emby_scan() now uses X-Emby-Token
consistently with emby_api(). Radarr v6 changed DownloadedMoviesScan to
require a path parameter — both cleanup scripts now use ProcessMonitoredDownloads
which achieves the same pre-flight intent without a path.
2026-06-27 12:28:58 -04:00
Gmer4Lfe 07b41559b6 Wire LIDARR_RECOVERY (and SONARR/RADARR) through detect_hosts()
All three *_RECOVERY vars were missing from detect_hosts() so the conf-file
values were never surfaced — LIDARR_RECOVERY defaulted to false even though
HOST1_LIDARR_RECOVERY=true, keeping Lidarr disabled in arrs_failed_stalled_recovery.
2026-06-27 12:16:51 -04:00
Gmer4Lfe 6feb7ff3fa Fix lidarr_missing_art: correct clearlogo.png filename and Music path map 2026-06-27 11:56:12 -04:00
Gmer4Lfe bafabe5fb3 Fix local-outside-function error in docker_network_connect and misuse of warn for background script launches in array_started 2026-06-27 11:06:10 -04:00
Gmer4Lfe ccaf19cfe4 Fix editor click alignment in Firefox and enable arr cleanup scripts in daily maintenance 2026-06-26 22:35:47 -04:00
Gmer4Lfe 97dfd522d0 Switch CLAUDE.md to reflect live dev/prod split 2026-06-26 21:51:29 -04:00
Gmer4Lfe f92ee4064b Add full banner headers to all scripts across the codebase
Every script now has the established header format: PURPOSE with ─────── separator,
OPERATIONAL MODEL, DESIGN PRINCIPLES, OPERATIONAL SAFEGUARDS, CONFIGURATION, and
RUNTIME MODES — structured with full ====== banner sections throughout.

Orchestrators converted from compact ── inline format to full banners. Stale
emby-fallback and dirty sync references removed from Plugin/user_script_plug-in.sh.
2026-06-26 18:50:05 -04:00
Gmer4Lfe 1003bee72a Replace emby dirty sync references with play_state_sync in comments and docs 2026-06-26 17:56:28 -04:00
Gmer4Lfe 638aba20c0 Rename Lldap-Gmer4Lfe to Lldap and guard local containers in cleanup 2026-06-26 17:56:20 -04:00
Gmer4Lfe fbe6a54e41 Fix three image cleanup gaps: weekly restart prune, mode-aware rebuild error, monthly orphan sweep
docker_weekly_restart.sh was missing the trailing dangling prune that daily_restart has.
docker_update.sh rebuild failure message always named docker_daily_restart.sh regardless of mode.
docker_prune_images.sh --all added to monthly — the only scheduled path that removes tagged orphan images.
2026-06-25 21:37:20 -04:00
Gmer4Lfe d058cf15c9 Add favorite sync to play_state_sync — union semantics, music first
Favorites on any server propagate to all others; never unmarks.
Covers MusicArtist, MusicAlbum, Movie, Series (Audio tracks future).
Provider map extended to include FAV_TYPES alongside SYNC_TYPES,
with Series/Episode TVDB IDs namespaced to avoid collisions.
2026-06-22 23:42:39 -04:00
Gmer4Lfe 4de10a7d01 Drop Audio from PLAY_SYNC_TYPES — music library too large for play state sync 2026-06-22 23:32:50 -04:00