# Ubuntu Based Kiosk **Current Version:** 1.0.2 (check script header for latest version) **Built with Claude Sonnet 4.6 AI assistance** **License:** GPL v3 - Keep derivatives open source **Repository:** https://github.com/outis1one/ubuntu-based-kiosk/ --- ## Target Systems - Ubuntu 24.04+ Server (minimal install recommended) - Raspberry Pi 4+ (with or without touchscreen) - *untested* - Laptops, desktops, all-in-ones, 2-in-1s - Touch support optional (works with keyboard/mouse) --- ## ⚠️ Security Notice **This is NOT suitable for secure locations or public kiosks.** - Do NOT use as a replacement for hardened kiosk solutions - Designed for home/office/trusted environments only - Use entirely at your own risk - No warranty or security guarantees provided --- ## Purpose Home/office kiosk for reusing old hardware, displaying: - Self-hosted services (Immich, MagicMirror2, Home Assistant, Plex, Jellyfin, Emby) - Web dashboards and digital signage - Photo slideshows and family calendars - Video conferencing (Jitsi, Zoom, Google Meet) - Any web-based content --- ## Quick Install ```bash # Install Ubuntu 24.04 Server # ***Do not use "kiosk" as a user name when installing, the script creates a restricted user named kiosk and the script will not install if the sudo user/user name when setting up the system is "kiosk".*** # Configure WiFi if no ethernet available # Enable SSH during installation # Download and run the latest installer LATEST=$(curl -fsSL https://api.github.com/repos/outis1one/ubuntu-based-kiosk/contents \ | grep -oP 'ubuntu-based-kiosk-v[0-9.]+\.sh' \ | grep -v beta | sort -V | tail -1) wget "https://github.com/outis1one/ubuntu-based-kiosk/raw/main/$LATEST" chmod +x "$LATEST" && ./"$LATEST" ``` The installer will guide you through configuration during setup. --- ## Core Features ### Multi-Site Management - **Single or multiple sites** with independent configurations - **Named sites** - Optional friendly names for easy identification in navigation menu - **Auto-rotation** - Sites rotate automatically based on duration - **Manual sites** - Duration = 0, accessible via swipe only, trigger inactivity timeout - **Hidden sites** - Duration = -1, PIN-protected access, trigger inactivity timeout - **Home URL** - Auto-return after inactivity on manual or hidden sites - **Pause functionality** - Temporarily pause rotation (configurable per-site) - **Navigation menu** - Quick access to all sites via key icon (top-left hot corner) ### Touch Controls - **2-finger horizontal swipe** - Switch between sites - **3-finger down swipe** - Toggle hidden tabs (PIN required to show, swipe again to hide) - **1-finger swipe** (dual mode) - Navigate within page (arrow keys) - **On-screen keyboard** - Auto-shows on text fields or click keyboard icon - **Navigation menu** - Click key icon (top-left) to access site list and gesture cheat sheet ### On-Screen Keyboard - **HTML-based keyboard** with full QWERTY layout - **Auto-show on text fields** (optional) - **30-second auto-close** after inactivity - **Shift/Caps Lock support** - **Special characters** via shift keys - Works alongside physical keyboard ### Password Protection & Lockout (all are optional) - **Session lockout** after configured inactivity - **Scheduled lockout** at specific time daily - **Display wake lockout** - Require password after display schedule - **Boot password** option - Require password on system startup - **Full screen blocking** during lockout (no content visible) ### Navigation Security - **Restricted** - Exact URL only, no link clicking - **Same-origin** - Links within same domain only (recommended) - **Open** - Unrestricted browsing (trusted environments only) ### Scheduling System (all are optional) - **Power schedule** - Auto-shutdown and RTC wake (hardware dependent) - **Display schedule** - Turn display off/on at specific times - **Quiet hours** - Mute audio or stop Squeezelite during hours - **Electron reload** - Periodic restart to prevent memory leaks ### Media Playback Intelligence - **Auto-detects playing media** (HTML5 video/audio, YouTube, Plex, Jellyfin, Emby) - **Pauses rotation** during media playback - **Grace period** after media stops - **Respects user activity** while watching --- ## Optional Add-ons ### Authentication #### Authelia Auto-Login (SSO) Automatically authenticates the kiosk against a self-hosted [Authelia](https://www.authelia.com) instance on every startup. The Authelia password is **not stored in plain text** — it is encrypted with AES-256-CBC using a key derived from the machine's unique `/etc/machine-id`, so the encrypted blob is useless on any other machine. **Access via menu:** `Addons → 5. Authelia Auto-Login` After running the addon it prints the full server-side setup, but the summary is below. ##### Kiosk side (SSH in and run the installer) ```bash ssh user@kiosk-machine ./$(ls ubuntu-based-kiosk-v*.sh | sort -V | tail -1) # Addons → 5. Authelia Auto-Login # Enter your Authelia URL, username, and password when prompted ``` ##### Authelia server side (Dockerized) **Step 1 — Generate the argon2 password hash** (run on your Docker host): ```bash docker run --rm authelia/authelia:latest \ authelia crypto hash generate argon2 \ --password 'yourpassword' ``` Copy the `$argon2id$...` output — that is your hash. **Step 2 — Add a kiosk user** to `~/docker/authelia/config/users.yml`: ```yaml kiosk: displayname: "Kiosk Display" password: '$argon2id$v=19$m=65536,t=3,p=4$' email: kiosk@local.com groups: - kiosk ``` **Step 3 — MERGE into `~/docker/authelia/config/configuration.yml`** (do not replace your existing config): **access_control** — Add the kiosk rule **ABOVE** any existing `two_factor` rule. Authelia applies rules top-down — first match wins: ```yaml access_control: default_policy: deny rules: # ADD THIS — kiosk can only do one_factor (no TOTP/WebAuthn via API) - domain: '*.yourdomain.com' subject: 'group:kiosk' policy: one_factor # Keep your existing rules below — e.g.: # - domain: '*.yourdomain.com' # policy: two_factor ``` **session** — Keep your existing session block as-is; no changes needed. The kiosk re-authenticates via API on every startup so session expiry barely matters for it. If you do **not** yet have a session block, add: ```yaml session: expiration: 8h inactivity: 1h remember_me: 7d cookies: - domain: yourdomain.com authelia_url: https://auth.yourdomain.com ``` **Step 4 — Restart Authelia:** ```bash docker compose restart authelia ``` ##### How it works On every kiosk startup, Electron calls Authelia's `/api/firstfactor` endpoint with `keepMeLoggedIn: true` **before** any sites load. Authelia responds with a `Set-Cookie` header that Electron absorbs into its default session. All BrowserViews then load with that session cookie already present. Because Electron's session persists to disk across reboots (`/home/kiosk/.config/kiosk-app/`), the cookie also survives restarts — the API call on startup just refreshes or extends it. ##### Authelia vs HTTP Basic Auth Both can be used at the same time — they serve different purposes: | Method | Where configured | When to use | |--------|-----------------|-------------| | **Authelia SSO** | `Addons → Authelia Auto-Login` (global) | Sites protected by an Authelia reverse proxy | | **HTTP Basic Auth** | Per-site username/password in tab config | Sites that show a browser popup asking for credentials | --- ### Communication - **Easy Asterisk Intercom** - Voice communication and intercom system - Downloads latest version from Easy Asterisk repository - Automatic update detection and installation - Configuration preservation during updates - Full Asterisk PBX integration - SIP/PJSIP support for IP phones and softphones ### Audio - **Lyrion Music Server (LMS)** - Formerly Logitech Media Server - **Squeezelite Player** - Network audio player for LMS - **PipeWire audio** - Modern Linux audio stack - **Volume controls** - Hardware button support ### Printing - **CUPS printing system** - **Network printer sharing** - **IPP Everywhere support** - **PDF printing** via cups-pdf ### Remote Access - **VNC** - x11vnc for remote desktop - **WireGuard VPN** - Config paste support - **Tailscale VPN** - Auth key support - **Netbird VPN** - Setup key support ### Advanced - **Emergency WiFi Hotspot** - Auto-starts if no internet after boot (configurable during install) - **Virtual Console Access** - Ctrl+Alt+F1-F8 terminal login (can enable/disable during install) - **Complete Uninstall** - Full system cleanup and kiosk removal - **SSH remote access** - For configuration and troubleshooting --- ## What This Script Installs ### Core Components - **Electron** v42.x (Chromium-based app framework) - **Node.js** v20.x with npm - **Openbox** - Lightweight window manager - **LightDM** - Display manager with autologin - **xorg** - X11 server and utilities - **unclutter** - Hide mouse cursor - **Hardware acceleration** - VAAPI, Mesa drivers ### Audio Stack - **PipeWire** - Modern audio/video server - **PipeWire-Pulse** - PulseAudio compatibility - **WirePlumber** - Session manager - **ALSA** utilities ### System Services - **systemd-timesyncd** - NTP time sync - **acpid** - Power button handling - **ufw** - Uncomplicated Firewall - **Network Manager** or netplan for networking ### Development Tools - **build-essential** - GCC, make, etc. - **Python 3** with evdev for PTT - **jq** - JSON processing --- ## System Behavior ### Security & Lockdown - **Autologin** as kiosk user - **Virtual consoles** (Ctrl+Alt+F1-F8) - Optional, configurable during install - **X server key combinations disabled** (Ctrl+Alt+Backspace) - **Right-click disabled** in kiosk app - **Screen blanking disabled** with schedule awareness - **DPMS management** - Aggressive keep-alive with schedule respect ### Audio Management - **PipeWire watchdog** - Auto-restart if audio fails - **Volume persistence** - Speakers 100%, Mic 100% and unmuted - **Quiet hours aware** - Respects audio schedules - **User services** - Audio runs under kiosk user ### Network - **WiFi configuration** - WPA2, netplan-based - **Multi-method WiFi scan** - nmcli, iw, wpa_cli fallbacks - **Watchdog support** - Auto-revert bad WiFi configs - **Emergency hotspot** - Fallback if no internet --- ## Maintenance & Troubleshooting ### Service Management ```bash # Restart kiosk display sudo systemctl restart lightdm # View Electron logs sudo tail -f /home/kiosk/electron.log # Check service status systemctl status lightdm systemctl status squeezelite sudo systemctl --user -M kiosk@ status pipewire ``` ### Common Issues **No display after boot:** ```bash # Check LightDM status sudo journalctl -u lightdm -n 50 # Verify kiosk user id kiosk # Check X11 authorization sudo -u kiosk DISPLAY=:0 xdpyinfo ``` **Audio not working:** ```bash # Check PipeWire (use menu: Advanced → Audio Diagnostics) sudo -u kiosk pactl info # Restart audio sudo systemctl restart lightdm ``` **Touch not working:** ```bash # List input devices xinput list # Check Electron logs for touch events sudo tail -f /home/kiosk/electron.log | grep TOUCH # Test gestures (should show in logs): # - 3-finger UP = "[TOUCH] 3-finger UP - show hidden tab" # - 3-finger DOWN = "[TOUCH] 3-finger DOWN - return to normal tabs" # - 2-finger HORIZONTAL = "[MANUAL] User switched tab..." ``` **Hidden sites not showing:** ```bash # Check PIN file exists ls -la /home/kiosk/kiosk-app/.jitsi-pin # View current PIN sudo cat /home/kiosk/kiosk-app/.jitsi-pin # Check for hidden sites in config sudo jq '.tabs[] | select(.duration == -1)' /home/kiosk/kiosk-app/config.json # Check if inactivity timeout is working on hidden tabs sudo tail -f /home/kiosk/electron.log | grep HOME # Should show: "[HOME] HIDDEN IDLE: Xm Ys / Ym Ys" ``` **Inactivity prompt not appearing:** ```bash # Check home tab configuration sudo jq '.homeTabIndex, .inactivityTimeout' /home/kiosk/kiosk-app/config.json # Watch for inactivity logging sudo tail -f /home/kiosk/electron.log | grep HOME # Manual site: "[HOME] 🏠 MANUAL IDLE: 1m 45s / 2m 0s" # Hidden site: "[HOME] 🏠 HIDDEN IDLE: 1m 45s / 2m 0s" # Prompt shown: "[HOME] 🔔 *** SHOWING PROMPT NOW (hidden tab) ***" ``` **Keyboard not appearing:** ```bash # Check keyboard button setting sudo grep enableKeyboardButton /home/kiosk/kiosk-app/config.json # View keyboard events sudo tail -f /home/kiosk/electron.log | grep KEYBOARD ``` ### Adding Printers to CUPS **1. Access CUPS Web Interface:** ``` http://:631/admin ``` Login with the username and password you used during Ubuntu installation. **2. Click "Add Printer"** **3. Find Your Printer URI** CUPS needs a device URI to connect to your printer. Here's how to find it: **For Network Printers (Most Common):** From Windows, find the printer's URI: 1. Right-click printer → **Printer Properties** → **Ports** tab 2. Look for the checked port, note the format: **HP Network Printers:** - Windows shows: `IP_192.168.1.100` or similar - CUPS URI: `hp:/net/?ip=192.168.1.100` - Alternative: `socket://192.168.1.100:9100` **Generic Network Printers (IPP):** - Windows shows: `http://192.168.1.100/ipp/print` or similar - CUPS URI: `ipp://192.168.1.100/ipp/print` - Alternative: `http://192.168.1.100:631/ipp/print` **Generic Network Printers (Socket/JetDirect):** - Windows shows: `Standard TCP/IP Port` on `192.168.1.100` - CUPS URI: `socket://192.168.1.100:9100` - Port 9100 is standard for HP JetDirect protocol **USB Printers:** - CUPS auto-detects these - URI looks like: `usb://HP/LaserJet%20P1102` - Select from "Local Printers" list in CUPS **4. Select Driver** After entering URI, CUPS will ask for a driver: - Search for your printer model - If not found, try "Generic PCL" or "Generic PostScript" - For HP printers, install `hplip`: `sudo apt install hplip` **5. Set as Default (Optional)** Administration → Set Default Printer **6. Print Test Page** Printers → Your Printer → Maintenance → Print Test Page **Quick Reference - Common URIs:** ```bash # HP Network Printer hp:/net/HP_LaserJet_P3015?ip=192.168.1.100 # Generic Network (Socket/JetDirect - Port 9100) socket://192.168.1.100:9100 # Generic Network (IPP) ipp://192.168.1.100/ipp/print # Shared Windows Printer smb://WORKGROUP/COMPUTER/PrinterName ``` **Troubleshooting:** - **Printer not responding:** Check firewall, ensure kiosk can ping printer IP - **Wrong driver:** Try Generic PostScript or PCL drivers - **Authentication failed:** Verify Windows printer sharing is enabled - **Can't find printer:** Use `lpinfo -v` to list all available devices --- ## Touch Gesture Quick Reference | Gesture | Fingers | Direction | Action | |---------|---------|-----------|--------| | Swipe | 2 | Left/Right | Switch between sites | | Swipe | 1 | Left/Right | Navigate within page (arrow keys) | | Swipe | 3 | Down | Toggle hidden tabs (PIN required) | **Keyboard Shortcuts:** - `Ctrl+Tab` or `Ctrl+]` - Next tab - `Ctrl+Shift+Tab` or `Ctrl+[` - Previous tab - `Alt+Right/Left` - Next/Previous tab - `F10` or `Ctrl+H` - Toggle hidden tabs - `Escape` - Return to normal tabs (from hidden) - `Ctrl+Alt+Delete` or `Ctrl+Alt+P` - Power menu - `Ctrl+K` - Toggle keyboard --- ### Menu System Access ```bash # Run installer script again to access menu ./$(ls ubuntu-based-kiosk-v*.sh | sort -V | tail -1) # Menu structure: # 1. Core Settings - Sites, WiFi, schedules, passwords, full reinstall, complete uninstall # 2. Addons - Authelia Auto-Login, Easy Asterisk Intercom, LMS, CUPS, VNC, VPNs # 3. Advanced - Diagnostics, logs, Electron updates, virtual consoles, emergency hotspot # 4. Restart Kiosk Display ``` ### Installing Easy Asterisk Intercom The Easy Asterisk Intercom addon provides voice communication capabilities to your kiosk system. **Access the addon menu:** ```bash ./$(ls ubuntu-based-kiosk-v*.sh | sort -V | tail -1) # Select: 2) Addons # Then: 4) Easy Asterisk Intercom ``` **Features:** - **Automatic installation** - Downloads and installs the latest version from the Easy Asterisk repository - **Update detection** - Checks for newer versions and prompts to update - **Safe re-runs** - Can be run multiple times without breaking existing configurations - **Config preservation** - Automatically backs up and restores configurations during updates - **Full Asterisk PBX** - Complete telephony features including SIP, extensions, voicemail **Installation behavior:** - **First install:** Downloads latest version from https://github.com/outis1one/easy-asterisk - **Already installed (latest):** Prompts to re-run installation (preserves configs) - **Update available:** Prompts to update and shows version difference - **All scenarios:** Configuration files in `/etc/asterisk/` and installation settings are preserved **Managing Easy Asterisk:** ```bash # Check installation status systemctl status asterisk # View Asterisk console asterisk -rvvv # Restart Asterisk systemctl restart asterisk # Configure intercom (rerun installation to update) ./$(ls ubuntu-based-kiosk-v*.sh | sort -V | tail -1) # Select: 2) Addons → 4) Easy Asterisk Intercom ``` **Installation location:** - Installation files: `/opt/easy-asterisk/` - Configuration: `/etc/asterisk/` - Version tracking: `/opt/easy-asterisk/.version` - Config backups: `/opt/easy-asterisk/config_backup/` ### Updating Electron ```bash # Via menu: Advanced → Manual Electron Update (RECOMMENDED) # The menu option automatically: # - Creates backup before updating # - Shows rollback instructions # - Handles permissions correctly # Or manually: cd /home/kiosk/kiosk-app sudo -u kiosk npm install electron@latest sudo systemctl restart lightdm ``` **Rollback if update fails:** The menu update creates automatic backups in `/home/kiosk/electron-backup-/` ```bash # 1. Stop display sudo systemctl stop lightdm # 2. Find your backup (most recent) ls -lt /home/kiosk/electron-backup-* | head -1 # 3. Restore backup files (replace timestamp with your backup) BACKUP=/home/kiosk/electron-backup- sudo cp $BACKUP/package.json /home/kiosk/kiosk-app/ sudo cp $BACKUP/package-lock.json /home/kiosk/kiosk-app/ 2>/dev/null || true # 4. Remove failed install and reinstall previous version sudo rm -rf /home/kiosk/kiosk-app/node_modules/electron cd /home/kiosk/kiosk-app && sudo -u kiosk npm install --unsafe-perm # 5. Fix permissions sudo chown root:root /home/kiosk/kiosk-app/node_modules/electron/dist/chrome-sandbox sudo chmod 4755 /home/kiosk/kiosk-app/node_modules/electron/dist/chrome-sandbox # 6. Restart display sudo systemctl start lightdm ``` --- ## Configuration Files ### Main Config `/home/kiosk/kiosk-app/config.json` ```json { "autoswitch": true, "swipeMode": "dual", "allowNavigation": "same-origin", "homeTabIndex": 0, "inactivityTimeout": 120, "enablePauseButton": true, "enableKeyboardButton": true, "enablePasswordProtection": false, "tabs": [ { "url": "https://example.com", "duration": 180, "username": "", "password": "" } ] } ``` ### Key Config Values - **duration**: `>0` = auto-rotate (seconds), `0` = manual only, `-1` = hidden - **swipeMode**: `"dual"` = 2-finger nav + 1-finger arrows, `"standard"` = 2-finger only - **allowNavigation**: `"restricted"` | `"same-origin"` | `"open"` - **homeTabIndex**: Tab to return to after inactivity (`-1` = disabled) - **inactivityTimeout**: Seconds before showing "still here?" prompt - **lockoutTimeout**: Minutes of inactivity before lockout (0 = disabled) - **lockoutAtTime**: Daily lockout time in `"HH:MM"` format - **requirePasswordOnBoot**: `true` = password required on system startup **Note:** Config files may contain `lockoutActiveStart` and `lockoutActiveEnd` fields from earlier versions. These are not currently functional and are ignored by the application. ### Hidden Sites PIN `/home/kiosk/kiosk-app/.jitsi-pin` The PIN file controls access to hidden sites (duration = -1): - **Default:** `1234` - **Configure via:** Main Menu → Core Settings → Sites → Configure Hidden Sites PIN - **Disable PIN:** Set content to `NOPIN` to allow any entry - **Custom PIN:** 4-8 digits ```bash # Set custom PIN echo "5678" | sudo -u kiosk tee /home/kiosk/kiosk-app/.jitsi-pin # Disable PIN protection echo "NOPIN" | sudo -u kiosk tee /home/kiosk/kiosk-app/.jitsi-pin ``` --- ## Advanced Features ### Site Duration Modes **Auto-Rotate (duration > 0):** - Site displays for specified seconds - Auto-advances to next rotation site - Pause button available - Respects media playback **Manual Only (duration = 0):** - Site accessible via swipe - Never auto-rotates - No pause button (not needed) - Can be set as Home URL - Triggers inactivity timeout (returns to home after idle time) **Hidden (duration = -1):** - Toggle visibility via 3-finger down swipe + PIN, or F10 key - Also use Escape key to return to normal tabs - PIN stored in `/home/kiosk/kiosk-app/.jitsi-pin` - Default PIN: 1234 (configurable via Sites menu) - PIN can be 4-8 digits or disabled completely - Hidden from normal rotation - **Triggers inactivity timeout** (returns to home after idle time, just like manual sites) #### Why Use Hidden Tabs? Hidden tabs are perfect for scenarios where you need access to sensitive or private content on a shared/public kiosk: **Private Communication:** - Video conferencing (Jitsi Meet, Zoom, Google Meet) - Private messaging or chat applications - Internal communication tools for staff only - Conference room scheduling interfaces **Administrative Access:** - Server administration panels (Proxmox, TrueNAS, router interfaces) - Security camera feeds - Home automation controls (Home Assistant, OpenHAB) - Network monitoring dashboards **Content Management:** - Digital signage content editors - Photo album management (Immich, PhotoPrism) - Media server administration (Plex, Jellyfin) - Calendar and scheduling updates **Secure Entertainment:** - Personal streaming accounts (prevent others from accessing your watch history) - Gaming platforms or cloud gaming services - Adult content controls (parental access only) - Personal social media (Facebook, Instagram, etc.) **Business Use Cases:** - Employee time tracking systems - Inventory management interfaces - Point-of-sale backend access - Staff scheduling and shift management **Example Scenarios:** 1. **Reception Kiosk:** Public-facing sites rotate (directory, weather, news), but staff can swipe up with PIN to access appointment scheduling, visitor management, or internal messaging. 2. **Family Room Display:** Displays photo slideshows, calendar, and weather, but parents can PIN-access streaming services, smart home controls, or security cameras. 3. **Digital Signage:** Publicly shows announcements and menus, but managers can PIN-access the content management system to make updates. 4. **Conference Room Display:** Shows meeting schedules and company news, but attendees can PIN-access video conferencing or presentation tools. The hidden tab system provides a balance between public accessibility and private functionality without needing to physically access a terminal or reconfigure the system. #### Why Use Named Sites? Named sites provide user-friendly labels that make navigation and management easier, especially when dealing with multiple similar URLs or complex web addresses. **Benefits:** - **Easier Navigation:** Click "Photo Gallery" instead of remembering "https://immich.mydomain.com:2283" - **Better Organization:** Quickly identify sites in the navigation menu without parsing URLs - **User-Friendly:** Non-technical users can find sites by name instead of domain - **Cleaner Display:** "Home Assistant" is more readable than "http://192.168.1.50:8123" - **Professional Appearance:** Business kiosks benefit from descriptive names over technical URLs **Use Cases:** **Home/Family Kiosks:** - "Photo Albums" instead of "https://photoprism.local:2342" - "Weather" instead of "https://weather.com" - "Security Cameras" instead of "http://192.168.1.100:8000" - "Smart Home" instead of "http://homeassistant.local:8123" **Business Kiosks:** - "Employee Portal" instead of "https://portal.company.com/employees" - "Time Clock" instead of "https://timekeeping.company.com/punch" - "Inventory System" instead of "http://10.0.0.50:8080/inventory" - "Customer Service" instead of "https://crm.company.com/support" **Digital Signage:** - "Dashboard 1" through "Dashboard 5" for rotating content - "Announcements" instead of "https://cms.local/public/announcements" - "Menu Board" instead of "http://192.168.1.75/menus/today" **Multi-Location Setups:** - "Building A Reception" and "Building B Reception" for identical URL structures - "Floor 1 Display" through "Floor 10 Display" for elevator kiosks - "East Wing" and "West Wing" for hospital navigation Names are completely optional - if left blank, the URL will be displayed as usual. Configure names during initial setup or update them later via: Core Settings → Sites → Update site names. ### Inactivity Extensions When "Are you still here?" prompt appears (on manual or hidden sites): - **"Yes, I'm still here"** - Reset all timers, stay on current page - **Time extensions** (15m, 30m, 1h, 2h) - Pause rotation and inactivity - **"No, go home"** - Return to home URL immediately - Extensions pause BOTH rotation and lockout timers - Maximum extension: 4 hours (safety timeout) **Triggers on:** - Manual sites (duration = 0) after inactivity timeout - Hidden sites (duration = -1) after inactivity timeout - Does NOT trigger on auto-rotating sites (duration > 0) - they use pause button instead ### Lockout Behavior **Triggers:** - Inactivity timeout expires (if configured) - Scheduled lockout time reached (if configured) - Display schedule wake-up (if password-on-wake enabled) - System boot (if requirePasswordOnBoot enabled) **During Lockout:** - Full black screen (no content visible) - All browser views detached for security - Password prompt displayed - Limited power menu (no Reload option to prevent bypass) - Rotation and timers paused **After Unlock:** - Returns to previous site - Timers reset - Normal operation resumes ### Media Detection Detects and pauses for: - HTML5 `