mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 08:36:13 +00:00
The web player is intrinsically LAN-resident: it reaches speakers directly and only delegates cloud-only features (e.g. TTS) to a possibly-remote AfterTouch service via --service-url. That is exactly what a cloud-hosted soundtouch-service cannot do, so the standalone player binary stays useful and is not being deprecated. Rename it to state its purpose, with a transition window so existing downloads keep working. - cmd/soundtouch-web -> cmd/soundtouch-player; CLI name is now soundtouch-player. When the binary is invoked under its old name it prints a one-line rename notice (filepath.Base(os.Args[0])). - Build/release both names from the same source: Makefile (build-player + build-web alias, dev-player* targets), Dockerfile (soundtouch-player image + transitional soundtouch-web image), release.yml and ci.yml (player + web artifacts, checksums, Docker images; release notes announce the rename). The soundtouch-web binary, image, and install script remain a transitional alias to be dropped in a future release (which will break stale fetch scripts and nudge users to the release notes). - scripts/raspberry-pi/install-player.sh is canonical; install-web.sh keeps working but warns. - Sweep docs, code comments, user-facing strings, and assets (soundtouch-web-ui.png, soundtouch-web-tunein.png, soundtouch-web-roadmap.md) to soundtouch-player; README documents the rename and why the player remains separate from the embedded /app. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
59 lines
2.3 KiB
Go
59 lines
2.3 KiB
Go
package soundtouchweb
|
|
|
|
import (
|
|
"log"
|
|
"strings"
|
|
)
|
|
|
|
// sanitizeLog strips newline characters from s to prevent log-injection
|
|
// (CodeQL go/log-injection). Values from speakers, HTTP requests, and
|
|
// external APIs may contain attacker-controlled newlines.
|
|
func sanitizeLog(s string) string {
|
|
s = strings.ReplaceAll(s, "\n", `\n`)
|
|
s = strings.ReplaceAll(s, "\r", `\r`)
|
|
|
|
return s
|
|
}
|
|
|
|
// logPlaybackRequest records what soundtouch-player is about to ask a speaker to
|
|
// play or switch to. A SoundTouch /select returns HTTP 200 even when the
|
|
// source is ultimately rejected: the failure only surfaces afterwards as a
|
|
// now_playing transition to an error source (see logNowPlayingError). So this
|
|
// line is frequently the only record of what was actually requested, and the
|
|
// pair (request here, error transition there) is what closes the loop when
|
|
// diagnosing source/playback failures.
|
|
//
|
|
// sourceAccount here is an account identifier (e.g. "AUX1" for a specific jack,
|
|
// or a placeholder username), not a bearer credential: the real OAuth tokens
|
|
// live in the service datastore, not in the ContentItem sent on /select. It is
|
|
// logged as-is so multi-account sources can be debugged.
|
|
func logPlaybackRequest(action, deviceID, source, sourceAccount, location, itemName string) {
|
|
log.Printf("[play] %s device=%q source=%q sourceAccount=%q location=%q itemName=%q",
|
|
sanitizeLog(action),
|
|
sanitizeLog(deviceID),
|
|
sanitizeLog(source),
|
|
sanitizeLog(sourceAccount),
|
|
sanitizeLog(location),
|
|
sanitizeLog(itemName),
|
|
)
|
|
}
|
|
|
|
// isErrorSource reports whether a now_playing source value indicates the
|
|
// speaker rejected or failed a selection rather than entering a normal state.
|
|
// It covers INVALID_SOURCE and the family of *_ERROR sources the firmware
|
|
// emits (e.g. UNKNOWN_SOURCE_ERROR).
|
|
func isErrorSource(source string) bool {
|
|
return source == "INVALID_SOURCE" || strings.HasSuffix(source, "_ERROR")
|
|
}
|
|
|
|
// logNowPlayingError logs when a speaker's now_playing enters an error source.
|
|
// Because /select returns 200 regardless, this asynchronous transition is the
|
|
// real signal that a selection failed on the device.
|
|
func logNowPlayingError(deviceID, source, sourceAccount string) {
|
|
log.Printf("[play] device=%q now_playing entered error source=%q sourceAccount=%q",
|
|
sanitizeLog(deviceID),
|
|
sanitizeLog(source),
|
|
sanitizeLog(sourceAccount),
|
|
)
|
|
}
|