From f2ee95a3b78935abad9660d0577f0db4ee2221a2 Mon Sep 17 00:00:00 2001 From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Mon, 25 May 2026 17:35:16 +0100 Subject: [PATCH] Update user service script to check for non-root use and for PipeWire or PulseAudio services/ [skip ci] --- user-service-install.sh | 146 +++++++++++++++++++++++++++++++++------- 1 file changed, 122 insertions(+), 24 deletions(-) diff --git a/user-service-install.sh b/user-service-install.sh index 4d09c937..95be0a95 100644 --- a/user-service-install.sh +++ b/user-service-install.sh @@ -7,6 +7,7 @@ SERVICE_SOURCE="./scripts/shairport-sync.user.service" USER_SYSTEMD_DIR="$HOME/.config/systemd/user" SERVICE_DEST="$USER_SYSTEMD_DIR/$SERVICE_NAME" APP_NAME="shairport-sync" +APP_DISPLAY_NAME="Shairport Sync" DRY_RUN=0 @@ -40,16 +41,24 @@ while [ $# -gt 0 ]; do shift done +# Check we are not running as root or under sudo +if [ "$(id -u)" -eq 0 ]; then + echo "[FAIL] This script must not be run as root or with sudo." >&2 + echo " [ADVICE] Please run it as the regular user who will own the service." >&2 + exit 1 +fi + echo "--------------------------------------------------" -echo "Systemd User Service Installer for $APP_NAME" +echo "Systemd User Service Installer for $APP_DISPLAY_NAME" echo "This script will:" -echo " - Check for system/initd conflicts" -echo " - Verify the app is not already running" +echo " - Check for systemd/initd conflicts" +echo " - Verify that Shairport Sync is not already running" +echo " - Detect PipeWire or PulseAudio" echo " - Install the user service" echo " - Enable it to run at login" if [ "$DRY_RUN" -eq 1 ]; then echo "" - echo "Dry-run mode: no changes will be made." + echo "Note: Dry-run mode: no changes will be made." fi echo "--------------------------------------------------" echo "" @@ -64,8 +73,9 @@ fi # Check for system-level service if systemctl is-enabled "$APP_NAME" >/dev/null 2>&1; then - echo "[FAIL] A system-level systemd service for '$APP_NAME' is currently enabled." >&2 - echo " [ADVICE] Please disable it before installing a user-level service." >&2 + echo "[FAIL] A system-level systemd service (\"$APP_NAME\") for $APP_DISPLAY_NAME is currently enabled." >&2 + echo " [ADVICE] Please disable it before installing a user-level service. For example, try:" >&2 + echo " [ADVICE] $ sudo systemctl disable --now $APP_NAME" >&2 exit 1 else echo "[OK] No conflicting system-level systemd service enabled." @@ -73,8 +83,9 @@ fi # Check for init.d service if [ -x "/etc/init.d/$APP_NAME" ]; then - echo "[FAIL] An init.d script for '$APP_NAME' exists at /etc/init.d/$APP_NAME." >&2 - echo " [ADVICE] Please remove or disable the init.d version before proceeding." >&2 + echo "[FAIL] An init.d script for $APP_DISPLAY_NAME exists at /etc/init.d/$APP_NAME." >&2 + echo " [ADVICE] Please remove or disable the init.d version before proceeding. For example, try:" >&2 + echo " [ADVICE] $ sudo rm /etc/init.d/$APP_NAME" >&2 exit 1 else echo "[OK] No conflicting init.d service found." @@ -82,16 +93,78 @@ fi # Note if the user-level service is already running if systemctl --user is-enabled "$APP_NAME" >/dev/null 2>&1; then - echo "[NOTE] A user-level systemd service for '$APP_NAME' is currently enabled." + echo "[NOTE] A user-level systemd service -- \"$APP_NAME\" -- for $APP_DISPLAY_NAME is currently enabled." fi # Check if the application is already running -if pgrep -x "$APP_NAME" >/dev/null 2>&1; then - echo "[FAIL] $APP_NAME is already running." >&2 +if pgrep -f "$APP_NAME" >/dev/null 2>&1; then + echo "[FAIL] $APP_DISPLAY_NAME is already running." >&2 echo " [ADVICE] Please stop $APP_NAME before proceeding." >&2 exit 1 else - echo "[OK] $APP_NAME is not currently running." + echo "[OK] $APP_DISPLAY_NAME is not running." +fi + +# Detect PipeWire or PulseAudio (prefer PipeWire) +AUDIO_BACKEND="" +AUDIO_REQUIRES="" +AUDIO_AFTER="" +AUDIO_OUTPUT_FLAG="" + +detect_pipewire() { + # Check if pipewire is running as a user service + if systemctl --user is-active pipewire >/dev/null 2>&1; then + return 0 + fi + # Also check if the process is running + if pgrep -x pipewire >/dev/null 2>&1; then + return 0 + fi + return 1 +} + +detect_pulseaudio() { + # Check if pulseaudio is running as a user service + if systemctl --user is-active pulseaudio >/dev/null 2>&1; then + return 0 + fi + # Also check if the process is running + if pgrep -x pulseaudio >/dev/null 2>&1; then + return 0 + fi + return 1 +} + +# Check whether shairport-sync was built with support for a given backend +# Usage: built_with_support e.g. built_with_support pipewire +built_with_support() { + shairport-sync -V 2>&1 | grep -qi "$1" +} + +if detect_pipewire; then + echo "[OK] PipeWire is running." + if built_with_support pipewire; then + echo "[OK] $APP_DISPLAY_NAME was built with PipeWire support -- it will be configured to use it." + AUDIO_BACKEND="pipewire" + AUDIO_REQUIRES="Requires=pipewire.service" + AUDIO_AFTER="After=pipewire.service" + AUDIO_OUTPUT_FLAG="-o pipewire" + else + echo "[NOTE] PipeWire is active, but $APP_DISPLAY_NAME was not built with PipeWire support -- falling back to the default ALSA audio output device." + fi +elif detect_pulseaudio; then + echo "[OK] PulseAudio is running." + if built_with_support pulseaudio; then + echo "[OK] $APP_DISPLAY_NAME was built with PulseAudio support -- it will be configured to use it." + AUDIO_BACKEND="pulseaudio" + AUDIO_REQUIRES="Requires=pulseaudio.service" + AUDIO_AFTER="After=pulseaudio.service" + AUDIO_OUTPUT_FLAG="-o pulseaudio" + else + echo "[NOTE] PulseAudio is active, but $APP_DISPLAY_NAME was not built with PulseAudio support -- falling back to the default ALSA audio output device." + fi +else + echo "[NOTE] Neither PipeWire nor PulseAudio detected -- $APP_DISPLAY_NAME will use the default ALSA audio output device." fi # Create directory @@ -105,7 +178,6 @@ if [ ! -d "$USER_SYSTEMD_DIR" ]; then echo "[FAIL] Failed to create directory $USER_SYSTEMD_DIR" >&2 exit 1 fi - fi else echo "[OK] User systemd directory already exists." @@ -117,30 +189,52 @@ if [ -d "$USER_SYSTEMD_DIR" ] && [ ! -w "$USER_SYSTEMD_DIR" ]; then exit 1 fi - # If the service file already exists, check that we can replace it - if [ -f "$SERVICE_DEST" ] && [ ! -w "$SERVICE_DEST" ]; then echo "[FAIL] The existing $SERVICE_DEST can not be replaced due to its ownership or permissions." >&2 echo " [ADVICE] Please delete $SERVICE_DEST or ensure it is owned and writable by user \"$(whoami)\" before proceeding." >&2 exit 1 fi -# Create the service file -if [ "$DRY_RUN" -eq 0 ]; then - echo "Creating service file at $SERVICE_DEST..." - cat > "$SERVICE_DEST" < "$SERVICE_DEST" if [ $? -eq 0 ]; then echo "[OK] Service file created." else @@ -179,5 +273,9 @@ if [ "$DRY_RUN" -eq 1 ]; then echo "Dry run completed successfully." else echo "Installation complete." - echo "The user-level systemd service for $APP_NAME is now installed and enabled." + if [ -n "$AUDIO_BACKEND" ]; then + echo "The user-level systemd service for $APP_DISPLAY_NAME is now installed and enabled, using $AUDIO_BACKEND." + else + echo "The user-level systemd service for $APP_DISPLAY_NAME is now installed and enabled." + fi fi