1(() => { 2 /* NEL_STATUS_START */ 3 const EMBEDDED_STATUS = {"generated_at":"2026-09-28T10:24:06.755354+01:00","updated_label":"10:24 BST","greeting":"Good morning, my champion.","line":"Core services are calm; Home PC is asleep and wake-ready.","overall":"ok","overall_label":"Online & watching","items":{"ultima":{"label":"OK","state":"ok"},"backups":{"label":"Fresh","state":"ok"},"homepc":{"label":"Wake-ready","state":"idle"},"comfyui":{"label":"Optional","state":"idle"}}}; 4 /* NEL_STATUS_END */ 5 6 /* ENSHROUDED_STATUS_START */ 7 const ENSHROUDED_STATUS = {"generated_at":"2026-09-28T10:24:06.755354+01:00","updated_label":"10:24 BST","state":"online","state_label":"Online","server_name":"Ultima Enshrouded","players":0,"max_players":16,"slots":16,"port":15637,"preset":"Default","text_chat":true,"voice_chat":false,"settings":{"Day":{"value":"30m","command":"Change Enshrouded day duration"},"Night":{"value":"12m","command":"Change Enshrouded night duration"},"Mining":{"value":"x3.0","command":"Change Enshrouded mining damage"},"Resources":{"value":"x3.0","command":"Change Enshrouded resource drops"},"Plant growth":{"value":"x1.5","command":"Change Enshrouded plant growth"},"Factory":{"value":"x2.0","command":"Change Enshrouded factory speed"},"Enemy dmg/hp":{"value":"x1 / x1","command":"Change Enshrouded enemy difficulty"},"Boss dmg/hp":{"value":"x1 / x1","command":"Change Enshrouded boss difficulty"},"Spawns":{"value":"Normal","command":"Change Enshrouded spawn amount"},"Aggro":{"value":"Normal","command":"Change Enshrouded aggro amount"}},"quick_actions":[{"label":"Status","command":"Enshrouded status"},{"label":"Backup","command":"Back up Enshrouded"},{"label":"Restart","command":"Restart Enshrouded"},{"label":"Settings","command":"What are the Enshrouded settings?"}],"commands":["Enshrouded status","Show Enshrouded logs","Show Enshrouded backups","Back up Enshrouded","Restart Enshrouded","What are the Enshrouded settings?","Make nights shorter/easier","Boost resources","Boost mining damage","Make enemies easier","Make enemies normal again","Set cozy preset","Restore default preset"]}; 8 /* ENSHROUDED_STATUS_END */ 9 10 function insertNelRoom() { 11 if (document.getElementById('nel-room-widget')) return; 12 const layout = document.getElementById('layout-groups'); 13 if (!layout) return; 14 15 const room = document.createElement('section'); 16 room.id = 'nel-room-widget'; 17 room.innerHTML = ` 18 <div class="nel-room-shell"> 19 <div class="nel-room-header"> 20 <div> 21 <div class="nel-room-eyebrow">NelPi companion space</div> 22 <h1>Nel's <span>Room</span></h1> 23 <p>A cozy dashboard nook for quick check-ins, service health, creative projects, and little fox-tail shortcuts.</p> 24 </div> 25 <div class="nel-room-status" data-state="loading"><span></span><strong>Checking statusâ¦</strong><small>Live-ish every 5 minutes</small></div> 26 </div> 27 <div class="nel-room-main"> 28 <div class="nel-room-avatar" aria-label="Nel portrait"></div> 29 <div class="nel-room-chat"> 30 <div class="nel-room-bubble"><strong id="nel-room-greeting">Hello, my champion.</strong><br><span id="nel-room-line">Gathering the den status nowâ¦</span></div> 31 <div class="nel-room-actions"> 32 <a href="https://ultima.nelpi.co.uk">Guild tools <small>Ultima dashboard</small></a> 33 <a href="https://home.nelpi.co.uk">Home scenes <small>Living room / automations</small></a> 34 <a href="#nel-room-widget">Wake studio <small>Ask Nel to wake Home PC</small></a> 35 <a href="https://www.youtube.com/">YouTube <small>Guides / music / chill</small></a> 36 </div> 37 </div> 38 <div class="nel-room-side"> 39 <div class="nel-room-mini" data-key="ultima"><b>Ultima</b><span>â¦</span></div> 40 <div class="nel-room-mini" data-key="backups"><b>Backups</b><span>â¦</span></div> 41 <div class="nel-room-mini" data-key="homepc"><b>Home PC</b><span>â¦</span></div> 42 <div class="nel-room-mini" data-key="comfyui"><b>ComfyUI</b><span>â¦</span></div> 43 </div> 44 </div> 45 <div id="enshrouded-control-card" class="enshrouded-card"></div> 46 </div>`; 47 layout.parentNode.insertBefore(room, layout); 48 updateNelRoomStatus(EMBEDDED_STATUS); 49 updateEnshroudedCard(ENSHROUDED_STATUS); 50 refreshNelRoomStatus(); 51 } 52 53 function updateEnshroudedCard(data) { 54 const card = document.getElementById('enshrouded-control-card'); 55 if (!card || !data) return; 56 const playerText = `${data.players ?? '?'} / ${data.max_players || data.slots || 16}`; 57 const settings = Object.entries(data.settings || {}).map(([key, item]) => { 58 const value = typeof item === 'object' ? item.value : item; 59 const command = typeof item === 'object' ? item.command : `Change Enshrouded ${key}`; 60 return `<button class="enshrouded-setting" data-copy-command="${c
60ommand}"><b>${key}</b><span>${value}</span><small>Edit via Nel</small></button>`; 61 }).join(''); 62 const quickActions = (data.quick_actions || []).map((action) => `<button class="enshrouded-action" data-copy-command="${action.command}">${action.label}</button>`).join(''); 63 const commands = (data.commands || []).map((command) => `<button data-copy-command="${command}">${command}</button>`).join(''); 64 card.innerHTML = ` 65 <div class="enshrouded-card-head"> 66 <div> 67 <div class="nel-room-eyebrow">Enshrouded server controls</div> 68 <h2>${data.server_name || 'Ultima Enshrouded'}</h2> 69 <p>Ask Nel in Discord for live changes. Public buttons only copy safe prompts; I do the backup/restart/apply step here.</p> 70 </div> 71 <div class="enshrouded-status-stack"> 72 <div class="enshrouded-pill" data-state="${data.state || 'online'}"><span></span>${data.state_label || 'Online'}</div> 73 <div class="enshrouded-player-pill">${playerText} players</div> 74 </div> 75 </div> 76 <div class="enshrouded-quick-actions">${quickActions}</div> 77 <div class="enshrouded-stats"> 78 <span><b>Port</b>${data.port || 15637}</span> 79 <span><b>Slots</b>${data.slots || 16}</span> 80 <span><b>Preset</b>${data.preset || 'Default'}</span> 81 <span><b>Text chat</b>${data.text_chat ? 'On' : 'Off'}</span> 82 </div> 83 <div class="enshrouded-settings">${settings}</div> 84 <details class="enshrouded-command-details"> 85 <summary>Show phrases I can say to Nel</summary> 86 <div class="enshrouded-commands">${commands}</div> 87 </details> 88 <small>Updated ${data.updated_label || 'recently'} · no RCON yet, so teleport/give-item waits for future support.</small>`; 89 90 card.querySelectorAll('[data-copy-command]').forEach((button) => { 91 button.addEventListener('click', async () => { 92 const command = button.dataset.copyCommand; 93 try { 94 await navigator.clipboard.writeText(command); 95 button.classList.add('copied'); 96 const old = button.textContent; 97 button.textContent = 'Copied: ' + command; 98 setTimeout(() => { button.classList.remove('copied'); button.textContent = old; }, 1300); 99 } catch (_) { 100 window.prompt('Copy this command for Nel:', command); 101 } 102 }); 103 }); 104 } 105 106 function updateNelRoomStatus(data) { 107 const room = document.getElementById('nel-room-widget'); 108 if (!room || !data) return; 109 const status = room.querySelector('.nel-room-status'); 110 status.dataset.state = data.overall || 'ok'; 111 status.querySelector('strong').textContent = data.overall_label || 'Online & watching'; 112 status.querySelector('small').textContent = data.updated_label ? `Updated ${data.updated_label}` : 'Live-ish status'; 113 114 room.querySelector('#nel-room-greeting').textContent = data.greeting || 'Hello, my champion.'; 115 room.querySelector('#nel-room-line').textContent = data.line || 'Services are calm, the fox den is lit, and shortcuts are ready.'; 116 117 Object.entries(data.items || {}).forEach(([key, item]) => { 118 const card = room.querySelector(`.nel-room-mini[data-key="${key}"]`); 119 if (!card) return; 120 card.dataset.state = item.state || 'idle'; 121 card.querySelector('span').textContent = item.label || 'OK'; 122 }); 123 } 124 125 async function refreshNelRoomStatus() { 126 try { 127 const response = await fetch(`/api/config/custom.js?t=${Date.now()}`, { cache: 'no-store' }); 128 if (!response.ok) return; 129 const text = await response.text(); 130 const match = text.match(/\/\* NEL_STATUS_START \*\/[\s\S]*?const EMBEDDED_STATUS = (\{[\s\S]*?\});[\s\S]*?\/\* NEL_STATUS_END \*\//); 131 if (!match) return; 132 updateNelRoomStatus(JSON.parse(match[1])); 133 } catch (_) {} 134 } 135 136 const timer = setInterval(() => { 137 insertNelRoom(); 138 if (document.getElementById('nel-room-widget')) clearInterval(timer); 139 }, 250); 140 window.addEventListener('load', insertNelRoom); 141 setInterval(refreshNelRoomStatus, 60_000); 142})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.