Platform-agnostic refactor: eliminate OS-specific hardcodes from core scripts

All bash scripts are now platform-neutral. Unraid-specific paths, commands,
and service checks moved to Plugin/unraid/adapter.sh. Core scripts call
platform_*() functions exclusively — no direct OS paths in runtime logic.

New adapter functions: platform_storage_path, platform_webui_install_path,
platform_scripts_dir_probe_cmd, platform_setup_db_path, platform_storage_healthy,
platform_is_service_enabled, platform_get_temp_thresholds, platform_disk_states_path,
platform_rebuild_container, platform_push_conf, platform_push_setup_state,
platform_get_templates_dir, platform_send_os_notification.

Partnership services stack (Emby/Jellyfin/Seerr/SeerrFin) added as third
onboarding stack alongside auth and arr stacks.
This commit is contained in:
Gmer4Lfe
2026-06-14 00:59:19 -04:00
parent fd1c4c7e3a
commit 27bfc21cb0
61 changed files with 411 additions and 444 deletions
+20 -12
View File
@@ -561,20 +561,23 @@ function vvDiskRow(disk) {
const tempColor = vvTempColor(tempC, disk.transport);
const tempStr = tempC !== null ? `${tempC}°` : '—';
const isParity = disk.role === 'parity';
const nameColor = isParity ? '#6a8faf' : '#aaa';
const failed = !isParity && disk.status && disk.status !== 'DISK_OK';
const nameColor = isParity ? '#6a8faf' : failed ? '#f44336' : '#aaa';
const pct = disk.pct ?? 0;
const barColor = isParity ? '#1e3a5a'
: failed ? '#f44336'
: pct >= vvThresholds.util_crit ? '#f44336'
: pct >= vvThresholds.util_warn ? '#ff9800'
: '#4caf50';
const barWidth = isParity ? '100' : pct;
const spinLabel = (!isParity && !disk.mounted) ? `<span style="color:#555;font-size:9px;margin-left:4px;">↓</span>` : '';
const failLabel = failed ? `<span style="color:#f44336;font-size:9px;margin-left:4px;">${disk.status === 'DISK_DSBL' ? 'emulated' : disk.status.replace('DISK_','').toLowerCase()}</span>` : '';
const right = isParity
? `<span style="color:#444;font-size:10px;">${vvFmt(disk.size_gb)}</span>`
: `<span style="color:#555;font-size:10px;">${vvFmt(disk.used_gb)} / ${vvFmt(disk.size_gb)}</span>`;
return `<div style="margin-bottom:7px;">
<div style="display:flex;justify-content:space-between;align-items:center;font-size:11px;margin-bottom:3px;">
<span style="color:${nameColor};display:flex;align-items:center;">${disk.name}${spinLabel}${vvIoChip(disk.device)}</span>
<span style="color:${nameColor};display:flex;align-items:center;">${disk.name}${spinLabel}${failLabel}${vvIoChip(disk.device)}</span>
${right}
<span style="color:${tempColor};font-size:10px;margin-left:6px;flex-shrink:0;">${tempStr}</span>
</div>
@@ -968,10 +971,8 @@ function vvPollMonitor() {
// ── Parity ──────────────────────────────────────────────────────────────
const par = d.parity ?? {};
(function() {
const valid = par.valid !== false;
const inProg = par.in_progress;
const validColor = valid ? '#4caf50' : '#f44336';
const validLabel = valid ? 'Parity is valid' : 'Parity is INVALID';
const valid = par.valid !== false;
const inProg = par.in_progress;
function vvRelTime(ts) {
if (!ts) return '';
@@ -999,15 +1000,21 @@ function vvPollMonitor() {
return new Date(ts * 1000).toLocaleString([], {weekday:'short',day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit'});
}
const exitColor = par.exit_label === 'Completed' ? '#4caf50' : par.exit_label === 'Aborted' ? '#ff9800' : '#f44336';
const errColor = (par.errors ?? 0) > 0 ? '#f44336' : '#444';
const speedStr = par.last_speed_mb ? ` · ${par.last_speed_mb} MB/s` : '';
const nextDate = vvFmtDate(par.next_ts);
const dueIn = vvDueIn(par.next_ts);
const parBannerCls = !valid ? 'vv-banner-err' : (par.errors ?? 0) > 0 ? 'vv-banner-warn' : 'vv-banner-ok';
const numDisabled = par.num_disabled ?? 0;
const numMissing = par.num_missing ?? 0;
const degraded = numDisabled > 0 || numMissing > 0;
const exitColor = par.exit_label === 'Completed' ? '#4caf50' : par.exit_label === 'Aborted' ? '#ff9800' : '#f44336';
const errColor = (par.errors ?? 0) > 0 ? '#f44336' : '#444';
const speedStr = par.last_speed_mb ? ` · ${par.last_speed_mb} MB/s` : '';
const nextDate = vvFmtDate(par.next_ts);
const dueIn = vvDueIn(par.next_ts);
const parBannerCls = !valid ? 'vv-banner-err' : degraded || (par.errors ?? 0) > 0 ? 'vv-banner-warn' : 'vv-banner-ok';
const emulLabel = numDisabled > 0 ? `<span style="font-size:11px;">Emulating ${numDisabled} disk${numDisabled !== 1 ? 's' : ''}</span>` : '';
const missingLabel = numMissing > 0 ? `<span style="font-size:11px;color:#f44336;">${numMissing} slot${numMissing !== 1 ? 's' : ''} missing</span>` : '';
let html = `<div class="vv-banner ${parBannerCls}">
<span>${valid ? '✓ Valid' : '✗ INVALID'}</span>
${emulLabel}${missingLabel}
${(par.errors ?? 0) > 0 ? `<span style="font-size:11px;">${par.errors} error${par.errors !== 1 ? 's' : ''}</span>` : ''}
</div>`;
@@ -1027,6 +1034,7 @@ function vvPollMonitor() {
<span style="color:${exitColor};">${par.exit_label ?? '—'}</span>
<span style="color:#555;">Errors</span>
<span style="color:${errColor};">${par.errors ?? 0}</span>
${numDisabled > 0 ? `<span style="color:#555;">Emulating</span><span style="color:#ff9800;">${numDisabled} disk${numDisabled !== 1 ? 's' : ''}</span>` : ''}
<span style="color:#555;">Next check</span>
<span style="color:#888;">${nextDate}</span>
</div>