diff --git a/docs/content/docs/guides/EXTERNAL-HOST-WALKTHROUGH.md b/docs/content/docs/guides/EXTERNAL-HOST-WALKTHROUGH.md index 5740462..5de1ded 100644 --- a/docs/content/docs/guides/EXTERNAL-HOST-WALKTHROUGH.md +++ b/docs/content/docs/guides/EXTERNAL-HOST-WALKTHROUGH.md @@ -34,10 +34,10 @@ sudo bash install.sh ``` The installer detects your Pi's architecture (armv7, arm64, or amd64), downloads -the binary, creates a `soundtouch` system user, and registers a systemd unit that -starts on boot. +the latest release binary, creates a `soundtouch` system user, and registers a +systemd unit that starts on boot. -To install a specific version: +To pin a specific version instead of the latest: ```bash sudo bash install.sh v0.111.3 diff --git a/docs/content/docs/guides/ON-DEVICE-INSTALL-WALKTHROUGH.md b/docs/content/docs/guides/ON-DEVICE-INSTALL-WALKTHROUGH.md index dc15c8a..64a9f94 100644 --- a/docs/content/docs/guides/ON-DEVICE-INSTALL-WALKTHROUGH.md +++ b/docs/content/docs/guides/ON-DEVICE-INSTALL-WALKTHROUGH.md @@ -81,7 +81,8 @@ currently running binary, and starts the service: rw && curl -sSL https://raw.githubusercontent.com/gesellix/Bose-SoundTouch/main/scripts/on-device-install/install.sh | sh ``` -To target a specific version instead of the default: +By default this installs the **latest release** — the script resolves it from +GitHub's `releases/latest` redirect. To target a specific version instead: ```bash # Via environment variable (works with pipe-to-sh) diff --git a/docs/content/docs/guides/RASPBERRY-PI.md b/docs/content/docs/guides/RASPBERRY-PI.md index af0bbd1..3cb0a23 100644 --- a/docs/content/docs/guides/RASPBERRY-PI.md +++ b/docs/content/docs/guides/RASPBERRY-PI.md @@ -13,6 +13,8 @@ Two scripts are available, one per binary: Both auto-detect CPU architecture (armv7 / arm64 / amd64), create a `soundtouch` system user, and install a systemd unit. They are safe to re-run for updates. +Run without a version argument, they install the **latest release** (resolved +from GitHub's `releases/latest` redirect); pass a tag to pin a specific version. Each installer has a matching uninstaller (`uninstall.sh`, `uninstall-player.sh`). > `install-web.sh` is the previous name for `install-player.sh`. It still works diff --git a/scripts/on-device-install/README.md b/scripts/on-device-install/README.md index 97023d9..c696da4 100644 --- a/scripts/on-device-install/README.md +++ b/scripts/on-device-install/README.md @@ -48,6 +48,10 @@ Then, run the following command to install AfterTouch on the device. rw && curl -sSL https://raw.githubusercontent.com/gesellix/Bose-SoundTouch/main/scripts/on-device-install/install.sh | sh ``` +This installs the **latest release** by default (the script resolves it from +GitHub's `releases/latest` redirect). To pin a specific version, see +[Updating AfterTouch](#updating-aftertouch) below. + After the installation check if you can access AfterTouch from your local device by navigating to `http://:8000`. If you can access the AfterTouch UI, you're good to go! ### If `http://:8000` fails: SSH port forwarding @@ -101,7 +105,11 @@ curl -sSLo install.sh https://raw.githubusercontent.com/gesellix/Bose-SoundTouch sh install.sh --version 0.111.3 ``` -Running **without** a version override installs the version hard-coded in the script (the latest release at the time the script was published). That default is updated with each release; if you're running from `main`, it reflects the most recent tagged version. +Running **without** a version override installs the latest release: the script +follows GitHub's `https://github.com/gesellix/Bose-SoundTouch/releases/latest` +redirect to discover the newest tag. If that lookup fails (offline, or a `curl` +build without `-w` support), it falls back to a pinned version baked into the +script. > **Tip — rollback:** if the new binary misbehaves, the installer left a `.backup` file alongside it: > ```bash diff --git a/scripts/on-device-install/install.sh b/scripts/on-device-install/install.sh index f7a5ab0..e8f1a47 100644 --- a/scripts/on-device-install/install.sh +++ b/scripts/on-device-install/install.sh @@ -1,15 +1,14 @@ #!/bin/bash set -eo pipefail -# Default version installed when no override is provided. Update this value -# each time a new release is cut so that running the canonical one-liner +# Version to install. Left empty by default so the canonical one-liner # curl -sSL .../install.sh | sh -# picks up the latest binary without extra arguments. +# resolves and installs the latest release automatically (see below). # -# Override via environment variable or the --version/-v flag: +# Pin a specific version via environment variable or the --version/-v flag: # VERSION=0.111.3 curl -sSL .../install.sh | sh # curl -sSL .../install.sh | sh -s -- --version 0.111.3 -VERSION=${VERSION:-0.111.3} +VERSION=${VERSION:-} # Parse optional command-line arguments so the script can be invoked as: # install.sh --version 0.111.3 @@ -27,6 +26,30 @@ while [ $# -gt 0 ]; do done GH_REPO=${GH_REPO:-gesellix/Bose-SoundTouch} + +# Used only when the latest-release lookup fails (offline / rate-limited / +# a curl without -w support). +FALLBACK_VERSION=${FALLBACK_VERSION:-0.111.3} + +# Resolve the latest release when no explicit version was provided, by +# following the stable redirect https://github.com//releases/latest +# -> .../releases/tag/vX.Y.Z and taking the tag from the final URL. The +# leading "v" is stripped because the URLs below add it back (v$VERSION). +if [ -z "$VERSION" ]; then + LATEST_URL="https://github.com/$GH_REPO/releases/latest" + echo "Resolving latest release via $LATEST_URL ..." + EFFECTIVE=$(curl -sSLI -o /dev/null -w '%{url_effective}' "$LATEST_URL" 2>/dev/null) || true + TAG=${EFFECTIVE##*/} + VER=${TAG#v} + case "$VER" in + [0-9]*.[0-9]*) VERSION="$VER" ;; + *) + VERSION="$FALLBACK_VERSION" + echo "WARNING: could not resolve latest release; using fallback $VERSION" >&2 + ;; + esac +fi + BINARY_URL=${BINARY_URL:-https://github.com/$GH_REPO/releases/download/v$VERSION/soundtouch-service-v$VERSION-linux-armv7} INIT_SCRIPT_URL=${INIT_SCRIPT_URL:-https://raw.githubusercontent.com/$GH_REPO/v$VERSION/scripts/on-device-install/aftertouch} diff --git a/scripts/raspberry-pi/README.md b/scripts/raspberry-pi/README.md index 40bef87..187eca8 100644 --- a/scripts/raspberry-pi/README.md +++ b/scripts/raspberry-pi/README.md @@ -26,7 +26,9 @@ curl -fsSL -o install-player.sh \ sudo bash install-player.sh ``` -Pass a version tag as the first argument to pin a specific release: +Both install the **latest release** by default (resolved from GitHub's +`releases/latest` redirect). Pass a version tag as the first argument to pin a +specific release: ```bash sudo bash install.sh v0.111.3 diff --git a/scripts/raspberry-pi/install-player.sh b/scripts/raspberry-pi/install-player.sh index a723328..244c397 100755 --- a/scripts/raspberry-pi/install-player.sh +++ b/scripts/raspberry-pi/install-player.sh @@ -32,11 +32,16 @@ set -euo pipefail # - Safe to re-run; it will update the binary, env file, and unit and restart. # ============================================================================== -VERSION="${1:-${VERSION:-v0.111.3}}" -# Normalize version prefix -if [[ ! "$VERSION" =~ ^v ]]; then +# Release to install. Empty means "resolve the latest release" (see +# resolve_version). Pass a tag/number as $1 or VERSION=... to pin a release. +VERSION="${1:-${VERSION:-}}" +# Normalize version prefix for an explicitly provided version. +if [[ -n "$VERSION" && ! "$VERSION" =~ ^v ]]; then VERSION="v${VERSION}" fi +GH_REPO="${GH_REPO:-gesellix/Bose-SoundTouch}" +# Used only when the latest-release lookup fails (offline / rate-limited). +FALLBACK_VERSION="${FALLBACK_VERSION:-v0.111.3}" SERVICE_NAME="${SERVICE_NAME:-soundtouch-player}" BIN_PATH="${BIN_PATH:-/usr/local/bin/soundtouch-player}" @@ -157,6 +162,40 @@ download_binary() { log "Installed binary to ${BIN_PATH}" } +resolve_version() { + # When no explicit version was given, resolve the latest release tag by + # following the documented stable redirect: + # https://github.com///releases/latest + # which 302-redirects to .../releases/tag/vX.Y.Z. We read the final URL and + # take the tag from it. Falls back to FALLBACK_VERSION on any failure + # (offline, rate-limited, no usable curl/wget). + if [[ -n "$VERSION" ]]; then + return + fi + + local latest_url="https://github.com/${GH_REPO}/releases/latest" + log "Resolving latest release via ${latest_url}" + + local effective="" tag="" + if command -v curl >/dev/null 2>&1; then + effective="$(curl -fsSLI -o /dev/null -w '%{url_effective}' "$latest_url" 2>/dev/null)" || true + else + # wget: don't follow the redirect, read the Location header instead. + effective="$(wget -S --max-redirect=0 -O /dev/null "$latest_url" 2>&1 \ + | awk 'tolower($1) ~ /location:/ {print $2}' | tr -d '\r' | tail -1)" || true + fi + tag="${effective##*/}" + + if [[ "$tag" =~ ^v?[0-9]+\.[0-9]+ ]]; then + [[ "$tag" =~ ^v ]] || tag="v${tag}" + VERSION="$tag" + log "Latest release is ${VERSION}" + else + VERSION="$FALLBACK_VERSION" + log "⚠️ Could not resolve latest release; falling back to ${VERSION}" + fi +} + self_update() { if [[ "$IS_SELF_UPDATE" == "true" ]]; then return @@ -324,6 +363,7 @@ main() { apt_install_if_missing curl fi + resolve_version self_update "$@" ensure_user_group diff --git a/scripts/raspberry-pi/install.sh b/scripts/raspberry-pi/install.sh index af36ffa..d0bdfa9 100644 --- a/scripts/raspberry-pi/install.sh +++ b/scripts/raspberry-pi/install.sh @@ -28,11 +28,16 @@ set -euo pipefail # - Safe to re-run; it will update binary/config/unit and restart the service. # ============================================================================== -VERSION="${1:-${VERSION:-v0.111.3}}" -# Normalize version prefix -if [[ ! "$VERSION" =~ ^v ]]; then +# Release to install. Empty means "resolve the latest release" (see +# resolve_version). Pass a tag/number as $1 or VERSION=... to pin a release. +VERSION="${1:-${VERSION:-}}" +# Normalize version prefix for an explicitly provided version. +if [[ -n "$VERSION" && ! "$VERSION" =~ ^v ]]; then VERSION="v${VERSION}" fi +GH_REPO="${GH_REPO:-gesellix/Bose-SoundTouch}" +# Used only when the latest-release lookup fails (offline / rate-limited). +FALLBACK_VERSION="${FALLBACK_VERSION:-v0.111.3}" SERVICE_NAME="${SERVICE_NAME:-soundtouch-service}" BIN_PATH="${BIN_PATH:-/usr/local/bin/soundtouch-service}" @@ -176,6 +181,40 @@ download_binary() { log "Installed binary to ${BIN_PATH}" } +resolve_version() { + # When no explicit version was given, resolve the latest release tag by + # following the documented stable redirect: + # https://github.com///releases/latest + # which 302-redirects to .../releases/tag/vX.Y.Z. We read the final URL and + # take the tag from it. Falls back to FALLBACK_VERSION on any failure + # (offline, rate-limited, no usable curl/wget). + if [[ -n "$VERSION" ]]; then + return + fi + + local latest_url="https://github.com/${GH_REPO}/releases/latest" + log "Resolving latest release via ${latest_url}" + + local effective="" tag="" + if command -v curl >/dev/null 2>&1; then + effective="$(curl -fsSLI -o /dev/null -w '%{url_effective}' "$latest_url" 2>/dev/null)" || true + else + # wget: don't follow the redirect, read the Location header instead. + effective="$(wget -S --max-redirect=0 -O /dev/null "$latest_url" 2>&1 \ + | awk 'tolower($1) ~ /location:/ {print $2}' | tr -d '\r' | tail -1)" || true + fi + tag="${effective##*/}" + + if [[ "$tag" =~ ^v?[0-9]+\.[0-9]+ ]]; then + [[ "$tag" =~ ^v ]] || tag="v${tag}" + VERSION="$tag" + log "Latest release is ${VERSION}" + else + VERSION="$FALLBACK_VERSION" + log "⚠️ Could not resolve latest release; falling back to ${VERSION}" + fi +} + self_update() { # If we are already a self-update re-exec, don't do it again if [[ "$IS_SELF_UPDATE" == "true" ]]; then @@ -364,6 +403,7 @@ main() { apt_install_if_missing curl fi + resolve_version self_update "$@" ensure_user_group