mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-08 19:58:11 +00:00
Four small, independent improvements bundled into one cut:
1. Restrict device discovery to SoundTouch-family services (#269/#359).
- mDNS now queries all three SoundTouch service-type variants in
parallel (_soundtouch._tcp, _bose-soundtouch._tcp, _soundtouchstick._tcp)
and deduplicates results by host:port. mDNS has no native wildcard
for service types, so we fan out one query per variant.
- UPnP/SSDP M-SEARCH receives a manufacturer/modelName check after
fetching the device description: devices whose manufacturer doesn't
contain "bose" AND whose model doesn't contain "soundtouch" are
rejected. Closes the loop on NorbertBauer's diagnostic bundle that
showed a Dreambox dm920 and Onkyo HT-R695 living under the default
account because they answered our generic MediaRenderer:1 probe.
2. New health check: default-account-contains-non-Bose-devices (#269).
Walks devices keyed under data/accounts/default/devices/, flags any
whose ProductCode/Name doesn't look SoundTouch, and offers an Evict
QuickFix. Bose devices still in default (legitimate pre-pair) are
intentionally ignored — that's the consistency check's domain.
3. Clipboard fallback for Copy buttons (#355). The two health-tab Copy
buttons used navigator.clipboard.writeText, which requires a secure
context. Over plain HTTP at a LAN IP the browser blocks it silently
and the button shows "Copy failed". New copyTextToClipboard helper
tries the modern API first, falls back to document.execCommand("copy")
via an off-screen textarea.
4. Web UI static-asset cache-busting (#345). dekiesel needed Ctrl+F5 to
see the v0.89 Download button after upgrade. The root HTML now
carries a ?v=<hash> query string on /web/js/script.js and
/web/css/style.css references. Hash is sha256 over the embedded asset
bodies, truncated to 12 hex chars — stable per binary, changes when
the assets change.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
59 lines
2.0 KiB
Go
59 lines
2.0 KiB
Go
// Package discovery provides device discovery functionality for Bose SoundTouch devices using mDNS and UPnP protocols.
|
|
package discovery
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
// SSDP multicast address and port
|
|
ssdpAddr = "239.255.255.250:1900"
|
|
|
|
// SoundTouch device URN for UPnP discovery
|
|
soundTouchURN = "urn:schemas-upnp-org:device:MediaRenderer:1"
|
|
|
|
// mDNS service type for SoundTouch devices (matches Bose's actual service name).
|
|
// Retained as the canonical / primary service type for log lines and tests;
|
|
// the full set of accepted variants lives in soundTouchServiceTypes below.
|
|
soundTouchServiceType = "_soundtouch._tcp"
|
|
soundTouchDomain = "local."
|
|
|
|
// Default discovery timeout
|
|
defaultTimeout = 5 * time.Second
|
|
|
|
// Default cache TTL
|
|
defaultCacheTTL = 30 * time.Second
|
|
)
|
|
|
|
// soundTouchServiceTypes lists every mDNS service-type variant we consider
|
|
// part of the SoundTouch family. mDNS doesn't support wildcard service-type
|
|
// queries at the protocol level, so the discovery code issues one parallel
|
|
// query per entry below and merges the results. Add new variants here as
|
|
// they're observed in the wild — Bose has historically advertised at
|
|
// least three:
|
|
//
|
|
// - _soundtouch._tcp : classic SoundTouch speakers (ST10/20/30, …)
|
|
// - _bose-soundtouch._tcp : seen on some newer firmware variants
|
|
// - _soundtouchstick._tcp : SoundTouch Wireless Adapter / dongle
|
|
var soundTouchServiceTypes = []string{
|
|
"_soundtouch._tcp",
|
|
"_bose-soundtouch._tcp",
|
|
"_soundtouchstick._tcp",
|
|
}
|
|
|
|
// isSoundTouchServiceName reports whether the mDNS service entry name
|
|
// belongs to any registered SoundTouch service type. Case-insensitive
|
|
// substring match — Bose's mDNS entries embed the service type after a
|
|
// dot (e.g. "Speaker._soundtouch._tcp.local.").
|
|
func isSoundTouchServiceName(name string) bool {
|
|
lower := strings.ToLower(name)
|
|
for _, t := range soundTouchServiceTypes {
|
|
if strings.Contains(lower, strings.ToLower(t)) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|