Migrate LMS/Squeezelite addon; fix is_service_enabled dead pre-check; bump to v2.9.0
New menus/addon_lms_squeezelite.sh: install/reconfigure/uninstall for an LMS (Lyrion/Logitech Media Server) server and a Squeezelite player, wired into install.sh's Addons menu. Squeezelite's own start script and systemd unit now go through $BIN_DIR/$SYSTEMD_DIR like every other addon instead of hardcoded /usr/local/bin and /etc/systemd/system; LMS's own apt repo/GPG key/ufw rules stay at their real fixed system paths, same approach as CUPS. Fixed a real unguarded-pipeline bug from the legacy install_lms(): `sudo systemctl enable "$service_name" 2>&1 | tee ...` made the exit status depend on tee (always 0) instead of systemctl enable, silently swallowing real enable/start failures. Now uses enable_and_start_units(). Fixed is_service_enabled() (shared helper, backported into the legacy script too): its list-unit-files pre-check never matched a bare service name, so it always fell through to "not enabled" regardless of the real state. Dropped the dead pre-check. Full command-level stubbed test suite covering install/reconfigure/ uninstall for both LMS and Squeezelite, including the repo-vs-fallback- download path, undetectable-service-name path, and enable/start-failure path. Full 12-suite regression + real end-to-end menu navigation via install.sh all pass. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VfsFSoRqfbRG7XAg5RoE7e
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Ubuntu Based Kiosk
|
||||
|
||||
**Current Version:** 2.8.0 (check script header for latest version)
|
||||
**Current Version:** 2.9.0 (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/
|
||||
@@ -1214,6 +1214,13 @@ terminal menu and the web UI, so they can't drift apart).
|
||||
Prompted the `save_config` merge fix above.
|
||||
- `menus/addon_remote_access.sh` — **Remote Access** (Addons): VNC,
|
||||
WireGuard, Tailscale, Netbird. The biggest Addon so far.
|
||||
- `menus/addon_lms_squeezelite.sh` — **LMS Server / Squeezelite Player**
|
||||
(Addons): install/reconfigure/uninstall for an LMS (Lyrion/Logitech
|
||||
Media Server) server the kiosk can host, and a Squeezelite player the
|
||||
kiosk can run against any LMS server on the LAN. Squeezelite's own
|
||||
start script and systemd unit go through `$BIN_DIR`/`$SYSTEMD_DIR`
|
||||
like every other addon; LMS's own apt repo/GPG key/ufw rules stay at
|
||||
their real fixed system paths, same as CUPS.
|
||||
- `install.sh` — entry point for the modular tool, now grouped **Core
|
||||
Settings / Addons / Advanced** like the legacy menu. Run it against an
|
||||
*already-installed* kiosk:
|
||||
@@ -1226,14 +1233,25 @@ terminal menu and the web UI, so they can't drift apart).
|
||||
**Honest status:** this does not yet replace first-time installation, or
|
||||
most of the old installer. `ubuntu-based-kiosk.sh` is still ~12,000
|
||||
lines and still contains its own unremoved, unmodified copies of every
|
||||
menu above (plus Upgrade, Reinstall, Uninstall, 2 more Addons, and the
|
||||
other 8 Advanced items — none of that has moved yet). Both copies
|
||||
coexist deliberately: the old ones stay until enough
|
||||
of Core Settings/Addons/Advanced is migrated to
|
||||
retire them in one pass, rather than leaving the legacy menu half-wired.
|
||||
Migration continues one `menus/*.sh` file at a time; first-time
|
||||
installation itself is the last and largest piece to move, if it moves
|
||||
at all.
|
||||
menu above (plus Upgrade, Reinstall, Uninstall, 1 more Addon — Easy
|
||||
Asterisk Intercom — and the other 8 Advanced items — none of that has
|
||||
moved yet). Both copies coexist deliberately: the old ones stay until
|
||||
enough of Core Settings/Addons/Advanced is migrated to retire them in
|
||||
one pass, rather than leaving the legacy menu half-wired. Migration
|
||||
continues one `menus/*.sh` file at a time; first-time installation
|
||||
itself is the last and largest piece to move, if it moves at all.
|
||||
|
||||
**Resolved (v2.9.0):** `is_service_enabled()` — shared by both scripts
|
||||
— had a pre-check (`systemctl list-unit-files | grep -q "^${service}\s"`)
|
||||
that never actually matched, since every call site passes a bare
|
||||
service name while `list-unit-files` lines start with
|
||||
`"$service.service"`. The function always fell through to `return 1`
|
||||
regardless of the real enabled state — under-reporting "enabled but not
|
||||
currently running" as "not installed" everywhere it's used, including
|
||||
LMS/Squeezelite's own status detection. Fixed in both `lib/config.sh`
|
||||
and `ubuntu-based-kiosk.sh` by dropping the dead pre-check —
|
||||
`systemctl is-enabled` already reports "not found" as a failure on its
|
||||
own.
|
||||
|
||||
**Resolved (v2.7.0):** the config-clobbering bug fixed in `lib/config.sh`
|
||||
(v2.6.0 — `save_config` silently deleting fields it doesn't know about,
|
||||
@@ -1248,9 +1266,14 @@ full migration pass.
|
||||
|
||||
## Project Status & Future Plans
|
||||
|
||||
**Current Version:** 2.8.0
|
||||
**Current Version:** 2.9.0
|
||||
|
||||
**Recent Updates (v2.8.0):**
|
||||
**Recent Updates (v2.9.0):**
|
||||
- **LMS Server / Squeezelite Player migrated** — install/reconfigure/uninstall for both, in `./install.sh`. Squeezelite's own start script and systemd unit now go through `$BIN_DIR`/`$SYSTEMD_DIR` like every other addon instead of hardcoded `/usr/local/bin`/`/etc/systemd/system`; LMS's own apt repo/GPG key/ufw rules stay at their real fixed system paths, same approach as CUPS.
|
||||
- **Bug fix:** the legacy `install_lms()` enabled/started the detected service via `sudo systemctl enable "$service_name" 2>&1 | tee /tmp/lms-enable.log` — piped through `tee`, the statement's exit status reflected `tee` (always 0), not `systemctl enable`, so a real enable/start failure was silently swallowed instead of falling through to a warning. Now uses the shared `enable_and_start_units()` helper.
|
||||
- **Bug fix (shared, backported to the legacy script too):** `is_service_enabled()`'s pre-check never matched a bare service name against `list-unit-files`' `"$service.service"` lines, so it always reported "not enabled" regardless of the real state. Dropped the dead pre-check — see "Modular Management" below.
|
||||
|
||||
**Previous (v2.8.0):**
|
||||
- **Remote Access migrated** — VNC, WireGuard, Tailscale, and Netbird, each with its own install/connect/status/uninstall flow. The biggest Addon so far. Tailscale/Netbird install via the vendors' own `curl | sh` method, preserved as-is.
|
||||
- **Important framework-level bug found and fixed:** `run_menu()`'s *handler* call has been crash-guarded since v2.1.0, but its *status function* call was still completely bare. A status function is meant to be read-only display, but a pipeline whose `grep` matches nothing (which `pipefail` turns into a failure even though the actual last command succeeds) would crash the **entire session**, not just fail to show status. Found while building `wireguard_status()` and verifying its exact failure mode rather than assuming it was covered. Fixed once, in the framework, protecting every status function across every menu — present and future. Also audited every existing status function for the same shape and fixed one real instance in `power_schedule_status()`.
|
||||
- Deduplicated: promoted `power_schedule.sh`'s `enable_and_start_timers()` to a shared `enable_and_start_units()` in `lib/menu.sh` (works for services now, not just timers) rather than writing the same helper a second time for VNC/WireGuard.
|
||||
|
||||
+6
-3
@@ -18,7 +18,8 @@
|
||||
# Power/Display/Quiet Hours.
|
||||
# Addons: CUPS Printing (menus/addon_cups.sh), Authelia Auto-Login
|
||||
# (menus/addon_authelia.sh), Remote Access - VNC/WireGuard/
|
||||
# Tailscale/Netbird (menus/addon_remote_access.sh).
|
||||
# Tailscale/Netbird (menus/addon_remote_access.sh), LMS Server /
|
||||
# Squeezelite Player (menus/addon_lms_squeezelite.sh).
|
||||
# Advanced: Diagnostics (menus/diagnostics.sh - system status/logs/
|
||||
# audio/network).
|
||||
#
|
||||
@@ -58,6 +59,8 @@ source "$SCRIPT_DIR/menus/addon_cups.sh"
|
||||
source "$SCRIPT_DIR/menus/addon_authelia.sh"
|
||||
# shellcheck source=menus/addon_remote_access.sh
|
||||
source "$SCRIPT_DIR/menus/addon_remote_access.sh"
|
||||
# shellcheck source=menus/addon_lms_squeezelite.sh
|
||||
source "$SCRIPT_DIR/menus/addon_lms_squeezelite.sh"
|
||||
|
||||
################################################################################
|
||||
# Preflight
|
||||
@@ -121,8 +124,8 @@ core_settings_menu() {
|
||||
}
|
||||
|
||||
addons_menu_builder() {
|
||||
MENU_LABELS=("CUPS Printing" "Authelia Auto-Login" "Remote Access")
|
||||
MENU_HANDLERS=(addon_cups_menu addon_authelia_menu remote_access_menu)
|
||||
MENU_LABELS=("CUPS Printing" "Authelia Auto-Login" "Remote Access" "LMS Server / Squeezelite Player")
|
||||
MENU_HANDLERS=(addon_cups_menu addon_authelia_menu remote_access_menu addon_lms_squeezelite_menu)
|
||||
}
|
||||
|
||||
addons_menu() {
|
||||
|
||||
@@ -78,6 +78,20 @@ is_service_active() {
|
||||
systemctl is-active --quiet "$service" 2>/dev/null
|
||||
}
|
||||
|
||||
# Whether a service is enabled (would start on boot), regardless of
|
||||
# whether it's currently running. The legacy script's version of this
|
||||
# pre-checked `systemctl list-unit-files | grep -q "^${service}\s"`
|
||||
# before calling is-enabled - but every call site passes a bare service
|
||||
# name (e.g. "squeezelite"), while list-unit-files lines start with
|
||||
# "squeezelite.service", so that regex never matched and the legacy
|
||||
# function always fell through to `return 1` no matter the real state.
|
||||
# `systemctl is-enabled` already reports "not found" as a failure on its
|
||||
# own, so the pre-check was both broken and unnecessary - dropped here.
|
||||
is_service_enabled() {
|
||||
local service="$1"
|
||||
systemctl is-enabled --quiet "$service" 2>/dev/null
|
||||
}
|
||||
|
||||
# Load every setting config.json has into the bash globals above.
|
||||
# Safe to call with no existing config file - leaves script defaults in place.
|
||||
load_existing_config() {
|
||||
|
||||
@@ -0,0 +1,344 @@
|
||||
#!/bin/bash
|
||||
################################################################################
|
||||
# menus/addon_lms_squeezelite.sh - "LMS Server / Squeezelite Player" addon.
|
||||
#
|
||||
# Two independent pieces sharing one menu, same as the legacy code: an LMS
|
||||
# (Lyrion/Logitech Media Server) server the kiosk can host, and a
|
||||
# Squeezelite player the kiosk can run to play music from any LMS server
|
||||
# (this one or another one on the LAN). LMS itself is a real apt-managed
|
||||
# subsystem with its own fixed paths (repo file, GPG keyring, ufw rules,
|
||||
# /etc/squeezeboxserver) - like CUPS, those get full command-level `sudo`/
|
||||
# `wget`/`apt` stubbing in tests rather than relocation. Squeezelite's own
|
||||
# start script and systemd unit are ours to place, so - like power_schedule
|
||||
# and the other addons - they go through $BIN_DIR/$SYSTEMD_DIR (lib/
|
||||
# config.sh) instead of hardcoded /usr/local/bin and /etc/systemd/system,
|
||||
# so tests can point them at a scratch directory.
|
||||
#
|
||||
# LMS ships under two package/service names depending on version -
|
||||
# "logitechmediaserver" (older) and "lyrionmusicserver" (the project's
|
||||
# current name after its rename) - so detection and every service call
|
||||
# has to check both.
|
||||
#
|
||||
# Depends on: lib/menu.sh, lib/config.sh being sourced first.
|
||||
################################################################################
|
||||
|
||||
lms_service_name() {
|
||||
if systemctl list-unit-files 2>/dev/null | grep -q "lyrionmusicserver.service"; then
|
||||
echo "lyrionmusicserver"
|
||||
elif systemctl list-unit-files 2>/dev/null | grep -q "logitechmediaserver.service"; then
|
||||
echo "logitechmediaserver"
|
||||
fi
|
||||
}
|
||||
|
||||
lms_is_installed() {
|
||||
is_service_active logitechmediaserver || is_service_enabled logitechmediaserver || \
|
||||
is_service_active lyrionmusicserver || is_service_enabled lyrionmusicserver
|
||||
}
|
||||
|
||||
lms_is_running() {
|
||||
is_service_active logitechmediaserver || is_service_active lyrionmusicserver
|
||||
}
|
||||
|
||||
squeezelite_is_installed() {
|
||||
is_service_active squeezelite || is_service_enabled squeezelite
|
||||
}
|
||||
|
||||
addon_lms_squeezelite_status() {
|
||||
if lms_is_installed; then
|
||||
echo "LMS Server: Installed"
|
||||
if lms_is_running; then
|
||||
echo " Status: Running"
|
||||
else
|
||||
echo " Status: Stopped"
|
||||
fi
|
||||
echo " Web: http://$(get_ip_address):9000"
|
||||
echo
|
||||
fi
|
||||
|
||||
if squeezelite_is_installed; then
|
||||
local player_name="Unknown"
|
||||
if [[ -f "$BIN_DIR/squeezelite-start.sh" ]]; then
|
||||
player_name=$(grep '^PLAYER_NAME=' "$BIN_DIR/squeezelite-start.sh" 2>/dev/null | cut -d'=' -f2 | tr -d '"' || echo "Unknown")
|
||||
fi
|
||||
echo "Squeezelite Player: Installed"
|
||||
if is_service_active squeezelite; then
|
||||
echo " Status: Running"
|
||||
else
|
||||
echo " Status: Stopped"
|
||||
fi
|
||||
echo " Name: $player_name"
|
||||
echo
|
||||
fi
|
||||
|
||||
echo "ℹ A server is needed to stream music. The kiosk can run the"
|
||||
echo " server (if sufficient resources) or connect to another server."
|
||||
}
|
||||
|
||||
addon_lms_squeezelite_menu_builder() {
|
||||
MENU_LABELS=("Install/Configure LMS Server" "Install/Configure Squeezelite Player")
|
||||
MENU_HANDLERS=(action_install_lms action_install_squeezelite)
|
||||
|
||||
if lms_is_installed; then
|
||||
MENU_LABELS+=("Uninstall LMS Server")
|
||||
MENU_HANDLERS+=(action_uninstall_lms)
|
||||
fi
|
||||
|
||||
if squeezelite_is_installed; then
|
||||
MENU_LABELS+=("Uninstall Squeezelite Player")
|
||||
MENU_HANDLERS+=(action_uninstall_squeezelite)
|
||||
fi
|
||||
}
|
||||
|
||||
addon_lms_squeezelite_menu() {
|
||||
run_menu "LMS SERVER / SQUEEZELITE PLAYER" addon_lms_squeezelite_menu_builder addon_lms_squeezelite_status
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Actions - LMS Server
|
||||
################################################################################
|
||||
|
||||
action_install_lms() {
|
||||
echo
|
||||
if lms_is_installed; then
|
||||
echo "LMS is already installed."
|
||||
if ask_yes_no "Reconfigure port?" "n"; then
|
||||
local new_port
|
||||
new_port=$(ask_integer "New HTTP port" 9000 1 65535)
|
||||
sudo sed -i "s/httpport:.*/httpport: $new_port/" /etc/squeezeboxserver/prefs/server.prefs 2>/dev/null || true
|
||||
sudo systemctl restart lyrionmusicserver 2>/dev/null || sudo systemctl restart logitechmediaserver 2>/dev/null || true
|
||||
log_success "LMS reconfigured on port $new_port"
|
||||
fi
|
||||
pause
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Installing Lyrion Music Server..."
|
||||
|
||||
# Try the repository method first.
|
||||
if wget -qO - https://debian.slimdevices.com/debian/squeezebox-keyring.gpg | sudo gpg --dearmor -o /usr/share/keyrings/lms-keyring.gpg 2>/dev/null; then
|
||||
echo "deb [signed-by=/usr/share/keyrings/lms-keyring.gpg] http://debian.slimdevices.com/debian stable main" | sudo tee /etc/apt/sources.list.d/lms.list
|
||||
# `|| true`: a bare, unguarded `apt update` failing here (bad
|
||||
# mirror, no network) would otherwise crash the whole session
|
||||
# under set -e instead of falling through to the direct-download
|
||||
# fallback below, which is exactly the degrade path this is
|
||||
# supposed to hit when the repository route doesn't work.
|
||||
sudo apt update 2>/dev/null || true
|
||||
if sudo apt install -y logitechmediaserver 2>/dev/null; then
|
||||
log_success "LMS installed via repository"
|
||||
else
|
||||
log_warning "Repository install failed, trying direct download..."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fall back to a direct .deb download if the repository didn't produce
|
||||
# either possible package.
|
||||
if ! command -v logitechmediaserver &>/dev/null && ! command -v lyrionmusicserver &>/dev/null; then
|
||||
local lms_deb="/tmp/lms.deb"
|
||||
echo "Downloading LMS v9.0.3..."
|
||||
if wget -q https://downloads.lms-community.org/LyrionMusicServer_v9.0.3/lyrionmusicserver_9.0.3_amd64.deb -O "$lms_deb"; then
|
||||
echo "Installing LMS package..."
|
||||
if sudo apt install -y "$lms_deb"; then
|
||||
log_success "LMS installed via direct download"
|
||||
else
|
||||
log_error "Failed to install LMS package"
|
||||
rm -f "$lms_deb"
|
||||
pause
|
||||
return 1
|
||||
fi
|
||||
rm -f "$lms_deb"
|
||||
else
|
||||
log_error "Failed to download LMS from lms-community.org"
|
||||
pause
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
local service_name
|
||||
service_name=$(lms_service_name)
|
||||
|
||||
if [[ -z "$service_name" ]]; then
|
||||
log_warning "Service file not found, checking installed files..."
|
||||
service_name=$(dpkg -L lyrionmusicserver logitechmediaserver 2>/dev/null | grep -m1 '\.service$' | xargs -r basename | sed 's/\.service$//' || echo "")
|
||||
fi
|
||||
|
||||
if [[ -z "$service_name" ]]; then
|
||||
log_error "Could not detect LMS service name"
|
||||
echo "Manual steps:"
|
||||
echo " 1. Find service: systemctl list-unit-files | grep -i lms"
|
||||
echo " 2. Enable: sudo systemctl enable SERVICE_NAME"
|
||||
echo " 3. Start: sudo systemctl start SERVICE_NAME"
|
||||
pause
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Using service: $service_name"
|
||||
# enable_and_start_units, not a bare `sudo systemctl enable ... | tee`
|
||||
# pipe: the legacy version's `2>&1 | tee /tmp/lms-enable.log` made the
|
||||
# whole statement's exit status depend on `tee` (always 0) rather than
|
||||
# `systemctl enable`, so a real enable/start failure was silently
|
||||
# swallowed instead of falling through to the warning below.
|
||||
if enable_and_start_units "$service_name"; then
|
||||
sudo ufw allow 9000/tcp comment 'LMS-HTTP' 2>/dev/null || true
|
||||
sudo ufw allow 3483/tcp comment 'LMS-SlimProto' 2>/dev/null || true
|
||||
sudo ufw allow 3483/udp comment 'LMS-Discovery' 2>/dev/null || true
|
||||
|
||||
log_success "LMS installed"
|
||||
echo " Web interface: http://$(get_ip_address):9000"
|
||||
else
|
||||
log_warning "LMS installed, but systemctl enable/start failed - check 'systemctl status $service_name'"
|
||||
fi
|
||||
|
||||
pause
|
||||
}
|
||||
|
||||
action_uninstall_lms() {
|
||||
echo
|
||||
ask_yes_no "Remove LMS Server?" "n" || { echo "Cancelled"; pause; return; }
|
||||
|
||||
local service_name
|
||||
service_name=$(lms_service_name)
|
||||
|
||||
if [[ -n "$service_name" ]]; then
|
||||
echo "Stopping $service_name..."
|
||||
sudo systemctl stop "$service_name" 2>/dev/null || true
|
||||
sudo systemctl disable "$service_name" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Try to remove both possible package names - only one will actually
|
||||
# be installed, the other is a harmless no-op.
|
||||
sudo apt remove -y lyrionmusicserver 2>/dev/null || true
|
||||
sudo apt remove -y logitechmediaserver 2>/dev/null || true
|
||||
|
||||
sudo rm -f /etc/apt/sources.list.d/lms.list
|
||||
sudo rm -f /usr/share/keyrings/lms-keyring.gpg
|
||||
|
||||
if ask_yes_no "Remove LMS data and configuration?" "n"; then
|
||||
sudo rm -rf /var/lib/squeezeboxserver
|
||||
sudo rm -rf /etc/squeezeboxserver
|
||||
log_success "LMS and data removed"
|
||||
else
|
||||
log_success "LMS removed (data preserved)"
|
||||
fi
|
||||
|
||||
pause
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Actions - Squeezelite Player
|
||||
################################################################################
|
||||
|
||||
action_install_squeezelite() {
|
||||
echo
|
||||
if squeezelite_is_installed; then
|
||||
echo "Squeezelite is already installed."
|
||||
ask_yes_no "Reconfigure?" "n" || { pause; return; }
|
||||
fi
|
||||
|
||||
if ! command -v squeezelite &>/dev/null; then
|
||||
if ! sudo apt install -y squeezelite; then
|
||||
log_error "squeezelite package installation failed"
|
||||
pause
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
local player_name
|
||||
player_name=$(ask_text "Player name" "Kiosk")
|
||||
|
||||
echo
|
||||
echo "LMS Server Configuration:"
|
||||
echo " Enter IP:PORT of your LMS server"
|
||||
echo " Leave blank for auto-discovery on LAN"
|
||||
echo
|
||||
local lms_server
|
||||
lms_server=$(ask_text "LMS Server (e.g., 192.168.1.100:3483)" "")
|
||||
|
||||
sudo tee "$BIN_DIR/squeezelite-start.sh" > /dev/null <<SQSTART
|
||||
#!/bin/bash
|
||||
|
||||
PLAYER_NAME="$player_name"
|
||||
LMS_SERVER="$lms_server"
|
||||
|
||||
for i in {1..20}; do
|
||||
pactl info >/dev/null 2>&1 && break
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if ! pactl info >/dev/null 2>&1; then
|
||||
logger "ERROR: Squeezelite - PipeWire not available"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -n "\$LMS_SERVER" ]]; then
|
||||
exec /usr/bin/squeezelite -n "\$PLAYER_NAME" -s "\$LMS_SERVER" -o pulse -a 80:4:: -b 512:1024 -C 5
|
||||
else
|
||||
exec /usr/bin/squeezelite -n "\$PLAYER_NAME" -o pulse -a 80:4:: -b 512:1024 -C 5
|
||||
fi
|
||||
SQSTART
|
||||
|
||||
sudo chmod +x "$BIN_DIR/squeezelite-start.sh"
|
||||
|
||||
local kiosk_uid
|
||||
kiosk_uid=$(id -u "$KIOSK_USER")
|
||||
|
||||
sudo tee "$SYSTEMD_DIR/squeezelite.service" > /dev/null <<EOF
|
||||
[Unit]
|
||||
Description=Squeezelite
|
||||
After=sound.target network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=$KIOSK_USER
|
||||
Environment="XDG_RUNTIME_DIR=/run/user/$kiosk_uid"
|
||||
ExecStartPre=/bin/sleep 10
|
||||
ExecStart=${BIN_DIR}/squeezelite-start.sh
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
sudo systemctl daemon-reload 2>/dev/null || true
|
||||
# Enable only, not start: squeezelite needs the kiosk user's real
|
||||
# session (PipeWire, XDG_RUNTIME_DIR) up first, which is why a reboot
|
||||
# is required below rather than starting it immediately.
|
||||
if ! sudo systemctl enable squeezelite 2>/dev/null; then
|
||||
log_warning "Squeezelite files written, but 'systemctl enable' failed - check 'systemctl status squeezelite'"
|
||||
fi
|
||||
|
||||
log_success "Squeezelite installed: $player_name"
|
||||
if [[ -n "$lms_server" ]]; then
|
||||
echo " Server: $lms_server"
|
||||
else
|
||||
echo " Server: Auto-discovery"
|
||||
fi
|
||||
echo
|
||||
echo "⚠️ IMPORTANT: Squeezelite requires a reboot to work properly"
|
||||
echo
|
||||
if ask_yes_no "Reboot now?" "n"; then
|
||||
echo "Rebooting in 5 seconds..."
|
||||
sleep 5
|
||||
sudo reboot
|
||||
else
|
||||
echo "⚠️ Remember to reboot before using Squeezelite"
|
||||
echo " Command: sudo reboot"
|
||||
fi
|
||||
|
||||
pause
|
||||
}
|
||||
|
||||
action_uninstall_squeezelite() {
|
||||
echo
|
||||
ask_yes_no "Remove Squeezelite Player?" "n" || { echo "Cancelled"; pause; return; }
|
||||
|
||||
sudo systemctl stop squeezelite 2>/dev/null || true
|
||||
sudo systemctl disable squeezelite 2>/dev/null || true
|
||||
sudo rm -f "$SYSTEMD_DIR/squeezelite.service"
|
||||
sudo rm -f "$BIN_DIR/squeezelite-start.sh"
|
||||
sudo apt remove -y squeezelite 2>/dev/null || true
|
||||
log_success "Squeezelite removed"
|
||||
|
||||
pause
|
||||
}
|
||||
+39
-8
@@ -1,8 +1,37 @@
|
||||
#!/bin/bash
|
||||
################################################################################
|
||||
### Ubuntu Based Kiosk v2.8.0 ###
|
||||
### Ubuntu Based Kiosk v2.9.0 ###
|
||||
################################################################################
|
||||
#
|
||||
# RELEASE v2.9.0 - LMS Server / Squeezelite Player Migrated;
|
||||
# is_service_enabled() Dead Pre-Check Fixed
|
||||
# - New in ./install.sh: LMS Server / Squeezelite Player
|
||||
# (menus/addon_lms_squeezelite.sh) - install/reconfigure/uninstall for
|
||||
# an LMS (Lyrion/Logitech Media Server) server the kiosk can host, and
|
||||
# a Squeezelite player the kiosk can run against any LMS server on the
|
||||
# LAN. Squeezelite's own start script and systemd unit now go through
|
||||
# $BIN_DIR/$SYSTEMD_DIR (lib/config.sh) instead of hardcoded
|
||||
# /usr/local/bin and /etc/systemd/system, matching every other addon;
|
||||
# LMS's own apt repo/GPG key/ufw rules stay at their real fixed system
|
||||
# paths, same as CUPS.
|
||||
# - Fixed a real unguarded-pipeline bug from the legacy install_lms():
|
||||
# `sudo systemctl enable "$service_name" 2>&1 | tee /tmp/lms-enable.log`
|
||||
# made the whole statement's exit status depend on `tee` (always 0)
|
||||
# instead of `systemctl enable`, so a real enable/start failure was
|
||||
# silently swallowed rather than falling through to a warning. Now
|
||||
# uses the shared enable_and_start_units() helper instead.
|
||||
# - Fixed is_service_enabled() (shared by both scripts): its pre-check
|
||||
# `systemctl list-unit-files | grep -q "^${service}\s"` never matched,
|
||||
# since every call site passes a bare service name (e.g.
|
||||
# "squeezelite") while list-unit-files lines start with
|
||||
# "squeezelite.service" - so the function always fell through to
|
||||
# `return 1` regardless of the real enabled state. `systemctl
|
||||
# is-enabled` already reports "not found" as a failure on its own, so
|
||||
# the dead pre-check is simply dropped. Backported here since it's the
|
||||
# same shared function in both scripts and the fix is low-risk
|
||||
# (behavior-preserving for every state except the one it was silently
|
||||
# getting wrong).
|
||||
#
|
||||
# RELEASE v2.8.0 - Remote Access Migrated (VNC/WireGuard/Tailscale/
|
||||
# Netbird); Framework-Level Status-Function Crash Fixed
|
||||
# - New in ./install.sh: Remote Access (menus/addon_remote_access.sh) -
|
||||
@@ -320,7 +349,7 @@ set -euo pipefail
|
||||
### SECTION 1: CONSTANTS & GLOBALS
|
||||
################################################################################
|
||||
|
||||
SCRIPT_VERSION="2.8.0"
|
||||
SCRIPT_VERSION="2.9.0"
|
||||
|
||||
# Resolve the real path to this script file.
|
||||
# When piped (curl|bash or wget|bash), BASH_SOURCE[0] is a pipe descriptor,
|
||||
@@ -578,12 +607,14 @@ is_service_active() {
|
||||
|
||||
is_service_enabled() {
|
||||
local service="$1"
|
||||
# Check if service file exists first
|
||||
if systemctl list-unit-files 2>/dev/null | grep -q "^${service}\s"; then
|
||||
systemctl is-enabled --quiet "$service" 2>/dev/null
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
# `systemctl is-enabled` already reports "not found" as a failure on
|
||||
# its own - no need for (and no correct way to write, given every
|
||||
# call site here passes a bare service name while list-unit-files
|
||||
# lines start with "$service.service") a pre-check via
|
||||
# list-unit-files. The previous "^${service}\s" pre-check never
|
||||
# matched, so this function always fell through to `return 1`
|
||||
# regardless of the real enabled state.
|
||||
systemctl is-enabled --quiet "$service" 2>/dev/null
|
||||
}
|
||||
|
||||
get_ip_address() {
|
||||
|
||||
Reference in New Issue
Block a user