Update user service script to check for non-root use and for PipeWire or PulseAudio services/ [skip ci]

This commit is contained in:
Mike Brady
2026-05-25 17:35:16 +01:00
committed by GitHub
parent e081e4a511
commit f2ee95a3b7
+122 -24
View File
@@ -7,6 +7,7 @@ SERVICE_SOURCE="./scripts/shairport-sync.user.service"
USER_SYSTEMD_DIR="$HOME/.config/systemd/user" USER_SYSTEMD_DIR="$HOME/.config/systemd/user"
SERVICE_DEST="$USER_SYSTEMD_DIR/$SERVICE_NAME" SERVICE_DEST="$USER_SYSTEMD_DIR/$SERVICE_NAME"
APP_NAME="shairport-sync" APP_NAME="shairport-sync"
APP_DISPLAY_NAME="Shairport Sync"
DRY_RUN=0 DRY_RUN=0
@@ -40,16 +41,24 @@ while [ $# -gt 0 ]; do
shift shift
done 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 "--------------------------------------------------"
echo "Systemd User Service Installer for $APP_NAME" echo "Systemd User Service Installer for $APP_DISPLAY_NAME"
echo "This script will:" echo "This script will:"
echo " - Check for system/initd conflicts" echo " - Check for systemd/initd conflicts"
echo " - Verify the app is not already running" echo " - Verify that Shairport Sync is not already running"
echo " - Detect PipeWire or PulseAudio"
echo " - Install the user service" echo " - Install the user service"
echo " - Enable it to run at login" echo " - Enable it to run at login"
if [ "$DRY_RUN" -eq 1 ]; then if [ "$DRY_RUN" -eq 1 ]; then
echo "" echo ""
echo "Dry-run mode: no changes will be made." echo "Note: Dry-run mode: no changes will be made."
fi fi
echo "--------------------------------------------------" echo "--------------------------------------------------"
echo "" echo ""
@@ -64,8 +73,9 @@ fi
# Check for system-level service # Check for system-level service
if systemctl is-enabled "$APP_NAME" >/dev/null 2>&1; then 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 "[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." >&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 exit 1
else else
echo "[OK] No conflicting system-level systemd service enabled." echo "[OK] No conflicting system-level systemd service enabled."
@@ -73,8 +83,9 @@ fi
# Check for init.d service # Check for init.d service
if [ -x "/etc/init.d/$APP_NAME" ]; then 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 "[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." >&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 exit 1
else else
echo "[OK] No conflicting init.d service found." echo "[OK] No conflicting init.d service found."
@@ -82,16 +93,78 @@ fi
# Note if the user-level service is already running # Note if the user-level service is already running
if systemctl --user is-enabled "$APP_NAME" >/dev/null 2>&1; then 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 fi
# Check if the application is already running # Check if the application is already running
if pgrep -x "$APP_NAME" >/dev/null 2>&1; then if pgrep -f "$APP_NAME" >/dev/null 2>&1; then
echo "[FAIL] $APP_NAME is already running." >&2 echo "[FAIL] $APP_DISPLAY_NAME is already running." >&2
echo " [ADVICE] Please stop $APP_NAME before proceeding." >&2 echo " [ADVICE] Please stop $APP_NAME before proceeding." >&2
exit 1 exit 1
else 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 <backend> 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 fi
# Create directory # Create directory
@@ -105,7 +178,6 @@ if [ ! -d "$USER_SYSTEMD_DIR" ]; then
echo "[FAIL] Failed to create directory $USER_SYSTEMD_DIR" >&2 echo "[FAIL] Failed to create directory $USER_SYSTEMD_DIR" >&2
exit 1 exit 1
fi fi
fi fi
else else
echo "[OK] User systemd directory already exists." echo "[OK] User systemd directory already exists."
@@ -117,30 +189,52 @@ if [ -d "$USER_SYSTEMD_DIR" ] && [ ! -w "$USER_SYSTEMD_DIR" ]; then
exit 1 exit 1
fi fi
# If the service file already exists, check that we can replace it # If the service file already exists, check that we can replace it
if [ -f "$SERVICE_DEST" ] && [ ! -w "$SERVICE_DEST" ]; then 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 "[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 echo " [ADVICE] Please delete $SERVICE_DEST or ensure it is owned and writable by user \"$(whoami)\" before proceeding." >&2
exit 1 exit 1
fi fi
# Create the service file
if [ "$DRY_RUN" -eq 0 ]; then
echo "Creating service file at $SERVICE_DEST..." # Build the service file content from a single source
cat > "$SERVICE_DEST" <<EOF if [ -n "$AUDIO_REQUIRES" ]; then
[Unit] UNIT_SECTION="[Unit]
Description=Shairport Sync - AirPlay Audio Receiver Description=Shairport Sync - AirPlay Audio Receiver
After=sound.target After=sound.target
$AUDIO_REQUIRES
$AUDIO_AFTER"
else
UNIT_SECTION="[Unit]
Description=Shairport Sync - AirPlay Audio Receiver
After=sound.target"
fi
if [ -n "$AUDIO_OUTPUT_FLAG" ]; then
EXEC_START="ExecStart=shairport-sync --log-to-syslog $AUDIO_OUTPUT_FLAG"
else
EXEC_START="ExecStart=shairport-sync --log-to-syslog"
fi
SERVICE_CONTENT="$UNIT_SECTION
[Service] [Service]
ExecStart=/usr/local/bin/shairport-sync --log-to-syslog $EXEC_START
[Install] [Install]
WantedBy=default.target WantedBy=default.target"
EOF
# Show the service file in dry-run mode, or write it for real
if [ "$DRY_RUN" -eq 1 ]; then
echo ""
echo "[DRY-RUN] Would write the following service file to $SERVICE_DEST:"
echo ""
echo "$SERVICE_CONTENT" | sed 's/^/ /'
echo ""
else
echo "Creating service file at $SERVICE_DEST..."
printf '%s\n' "$SERVICE_CONTENT" > "$SERVICE_DEST"
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echo "[OK] Service file created." echo "[OK] Service file created."
else else
@@ -179,5 +273,9 @@ if [ "$DRY_RUN" -eq 1 ]; then
echo "Dry run completed successfully." echo "Dry run completed successfully."
else else
echo "Installation complete." 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 fi