mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-19 00:56:16 +00:00
feat(cli)!: deprecate speaker-based station search in favour of find
The `find` family runs the search inside the CLI, querying the radio provider's public API directly (no speaker cloud, no soundtouch-service). Make it the canonical path and deprecate the speaker-based search family. - Add `find-tunein` and `find-radiobrowser` siblings; refactor the find actions onto a shared `runFind` helper (all support `--more`). - Rename the unreleased `search-radiobrowser` to `find-radiobrowser`. - Deprecate `search`, `search-tunein`, `search-pandora`, `search-spotify`: they keep working but print a stderr deprecation notice (new `PrintDeprecation` helper) pointing at the `find*` replacement. Pandora and Spotify have no built-in equivalent yet (they need the speaker + account), so their notices say so. - Docs: lead with the `find` family as recommended; mark the speaker-based search commands deprecated; drop the misleading "service-side" wording in favour of "built-in / queries the provider directly". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
21efb412fe
commit
c7eda7ed7b
@@ -12,6 +12,12 @@ import (
|
||||
|
||||
// searchStations handles searching for stations across different sources
|
||||
func searchStations(c *cli.Context) error {
|
||||
PrintDeprecation(
|
||||
"station search",
|
||||
"It asks the speaker to search, which fails when the speaker's cloud is gone.",
|
||||
`soundtouch-cli station find --provider tunein --query "<your search>"`,
|
||||
)
|
||||
|
||||
source := c.String("source")
|
||||
sourceAccount := c.String("source-account")
|
||||
searchTerm := c.String("query")
|
||||
@@ -51,6 +57,12 @@ func searchStations(c *cli.Context) error {
|
||||
|
||||
// searchTuneIn handles searching TuneIn specifically
|
||||
func searchTuneIn(c *cli.Context) error {
|
||||
PrintDeprecation(
|
||||
"station search-tunein",
|
||||
"It asks the speaker to search, which fails when the speaker's cloud is gone.",
|
||||
`soundtouch-cli station find-tunein --query "<your search>"`,
|
||||
)
|
||||
|
||||
searchTerm := c.String("query")
|
||||
|
||||
if searchTerm == "" {
|
||||
@@ -86,6 +98,12 @@ func searchTuneIn(c *cli.Context) error {
|
||||
|
||||
// searchPandora handles searching Pandora specifically
|
||||
func searchPandora(c *cli.Context) error {
|
||||
PrintDeprecation(
|
||||
"station search-pandora",
|
||||
"There is no built-in Pandora search yet (it requires the speaker and your account).",
|
||||
"",
|
||||
)
|
||||
|
||||
sourceAccount := c.String("source-account")
|
||||
searchTerm := c.String("query")
|
||||
|
||||
@@ -127,6 +145,12 @@ func searchPandora(c *cli.Context) error {
|
||||
|
||||
// searchSpotify handles searching Spotify specifically
|
||||
func searchSpotify(c *cli.Context) error {
|
||||
PrintDeprecation(
|
||||
"station search-spotify",
|
||||
"There is no built-in Spotify search yet (it requires the speaker and your account).",
|
||||
"",
|
||||
)
|
||||
|
||||
sourceAccount := c.String("source-account")
|
||||
searchTerm := c.String("query")
|
||||
|
||||
@@ -531,31 +555,18 @@ func bmxNavCursor(section *models.BmxNavSection) string {
|
||||
return parsed.Query().Get("cursor")
|
||||
}
|
||||
|
||||
// searchService is the action for `station search` with --provider / --query / --more.
|
||||
// It uses the service-side stations package (works even when the speaker's cloud is dead).
|
||||
func searchService(c *cli.Context) error {
|
||||
providerStr := c.String("provider")
|
||||
query := c.String("query")
|
||||
more := c.Bool("more")
|
||||
|
||||
// runFind performs a built-in station search for the given provider and
|
||||
// prints the results. The search runs inside the CLI itself, querying the
|
||||
// radio provider's public API directly — it needs neither the speaker's
|
||||
// cloud nor a running soundtouch-service. When more is true it follows up
|
||||
// to three additional result pages while a next cursor is available.
|
||||
func runFind(provider stations.Provider, label, query string, more bool) error {
|
||||
if query == "" {
|
||||
PrintError("Search query is required")
|
||||
return fmt.Errorf("search query cannot be empty")
|
||||
}
|
||||
|
||||
var provider stations.Provider
|
||||
|
||||
switch strings.ToLower(providerStr) {
|
||||
case "tunein":
|
||||
provider = stations.ProviderTuneIn
|
||||
case "radiobrowser":
|
||||
provider = stations.ProviderRadioBrowser
|
||||
default:
|
||||
PrintError(fmt.Sprintf("Unknown provider %q: must be 'tunein' or 'radiobrowser'", providerStr))
|
||||
return fmt.Errorf("unknown provider: %s", providerStr)
|
||||
}
|
||||
|
||||
fmt.Printf("Searching %s for: %s\n", providerStr, query)
|
||||
fmt.Printf("Searching %s for: %s\n", label, query)
|
||||
|
||||
resp, err := stations.Search(provider, query)
|
||||
if err != nil {
|
||||
@@ -569,7 +580,6 @@ func searchService(c *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Follow up to 3 additional pages while a next cursor is available.
|
||||
const maxExtraPages = 3
|
||||
for page := 0; page < maxExtraPages; page++ {
|
||||
// Find a cursor from any section that has one.
|
||||
@@ -599,25 +609,36 @@ func searchService(c *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// searchServiceRadioBrowser is the action for `station search-radiobrowser`.
|
||||
// It searches via the service-side RadioBrowser backend.
|
||||
func searchServiceRadioBrowser(c *cli.Context) error {
|
||||
query := c.String("query")
|
||||
// findStations is the action for the unified `station find` with
|
||||
// --provider / --query / --more.
|
||||
func findStations(c *cli.Context) error {
|
||||
providerStr := c.String("provider")
|
||||
|
||||
if query == "" {
|
||||
PrintError("Search query is required")
|
||||
return fmt.Errorf("search query cannot be empty")
|
||||
var (
|
||||
provider stations.Provider
|
||||
label string
|
||||
)
|
||||
|
||||
switch strings.ToLower(providerStr) {
|
||||
case "tunein":
|
||||
provider, label = stations.ProviderTuneIn, "TuneIn"
|
||||
case "radiobrowser":
|
||||
provider, label = stations.ProviderRadioBrowser, "Radio Browser"
|
||||
default:
|
||||
PrintError(fmt.Sprintf("Unknown provider %q: must be 'tunein' or 'radiobrowser'", providerStr))
|
||||
return fmt.Errorf("unknown provider: %s", providerStr)
|
||||
}
|
||||
|
||||
fmt.Printf("Searching Radio Browser for: %s\n", query)
|
||||
return runFind(provider, label, c.String("query"), c.Bool("more"))
|
||||
}
|
||||
|
||||
resp, err := stations.Search(stations.ProviderRadioBrowser, query)
|
||||
if err != nil {
|
||||
PrintError(fmt.Sprintf("Search failed: %v", err))
|
||||
return err
|
||||
}
|
||||
// findTuneIn is the action for `station find-tunein` (built-in TuneIn search).
|
||||
func findTuneIn(c *cli.Context) error {
|
||||
return runFind(stations.ProviderTuneIn, "TuneIn", c.String("query"), c.Bool("more"))
|
||||
}
|
||||
|
||||
printBmxNavResults(resp)
|
||||
|
||||
return nil
|
||||
// findRadioBrowser is the action for `station find-radiobrowser`
|
||||
// (built-in Radio Browser search).
|
||||
func findRadioBrowser(c *cli.Context) error {
|
||||
return runFind(stations.ProviderRadioBrowser, "Radio Browser", c.String("query"), c.Bool("more"))
|
||||
}
|
||||
|
||||
@@ -340,6 +340,22 @@ func PrintWarning(message string) {
|
||||
fmt.Printf("⚠️ %s\n", message)
|
||||
}
|
||||
|
||||
// PrintDeprecation prints a deprecation notice to stderr (so it does not
|
||||
// pollute piped stdout output). reason explains why the command is going
|
||||
// away; newUsage is an optional replacement example — pass "" when there
|
||||
// is no replacement yet.
|
||||
func PrintDeprecation(command, reason, newUsage string) {
|
||||
fmt.Fprintf(os.Stderr, "⚠️ '%s' is deprecated and will be removed in a future release.\n", command)
|
||||
|
||||
if reason != "" {
|
||||
fmt.Fprintf(os.Stderr, " %s\n", reason)
|
||||
}
|
||||
|
||||
if newUsage != "" {
|
||||
fmt.Fprintf(os.Stderr, " Use instead:\n %s\n", newUsage)
|
||||
}
|
||||
}
|
||||
|
||||
// showVersionInfo displays detailed version information including build details
|
||||
func showVersionInfo(_ *cli.Context) error {
|
||||
fmt.Printf("%s version %s\n", os.Args[0], version)
|
||||
|
||||
+67
-39
@@ -589,9 +589,72 @@ func main() {
|
||||
Aliases: []string{"st"},
|
||||
Usage: "Search and manage stations",
|
||||
Subcommands: []*cli.Command{
|
||||
// Built-in search ("find" family): runs inside the CLI,
|
||||
// querying the radio provider's public API directly. No
|
||||
// speaker cloud and no soundtouch-service required.
|
||||
{
|
||||
Name: "find",
|
||||
Usage: "Find stations directly (built-in tunein or radiobrowser search; no speaker needed)",
|
||||
Action: findStations,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "provider",
|
||||
Usage: "Station provider: tunein or radiobrowser",
|
||||
Value: "tunein",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "query",
|
||||
Aliases: []string{"q"},
|
||||
Usage: "Search query",
|
||||
Required: true,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "more",
|
||||
Usage: "Follow up to 3 additional result pages when available",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "find-tunein",
|
||||
Usage: "Find TuneIn stations directly (built-in search; no speaker needed)",
|
||||
Action: findTuneIn,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "query",
|
||||
Aliases: []string{"q"},
|
||||
Usage: "Search query",
|
||||
Required: true,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "more",
|
||||
Usage: "Follow up to 3 additional result pages when available",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "find-radiobrowser",
|
||||
Usage: "Find Radio Browser stations directly (built-in search; no speaker needed)",
|
||||
Action: findRadioBrowser,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "query",
|
||||
Aliases: []string{"q"},
|
||||
Usage: "Search query",
|
||||
Required: true,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "more",
|
||||
Usage: "Follow up to 3 additional result pages when available",
|
||||
},
|
||||
},
|
||||
},
|
||||
// Deprecated speaker-based search commands. They ask the
|
||||
// speaker to search, which fails once its cloud is gone.
|
||||
// Prefer the "find" family above. Kept for now; each emits
|
||||
// a deprecation notice on stderr.
|
||||
{
|
||||
Name: "search",
|
||||
Usage: "Search for stations and content",
|
||||
Usage: "[DEPRECATED] Search via the speaker; use 'station find' instead",
|
||||
Action: searchStations,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
@@ -612,31 +675,9 @@ func main() {
|
||||
},
|
||||
Before: RequireHost,
|
||||
},
|
||||
{
|
||||
Name: "find",
|
||||
Usage: "Find stations via the AfterTouch service (tunein or radiobrowser)",
|
||||
Action: searchService,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "provider",
|
||||
Usage: "Station provider: tunein or radiobrowser",
|
||||
Value: "tunein",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "query",
|
||||
Aliases: []string{"q"},
|
||||
Usage: "Search query",
|
||||
Required: true,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "more",
|
||||
Usage: "Follow up to 3 additional result pages when available",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "search-tunein",
|
||||
Usage: "Search TuneIn stations",
|
||||
Usage: "[DEPRECATED] Search TuneIn via the speaker; use 'station find-tunein' instead",
|
||||
Action: searchTuneIn,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
@@ -650,7 +691,7 @@ func main() {
|
||||
},
|
||||
{
|
||||
Name: "search-pandora",
|
||||
Usage: "Search Pandora stations",
|
||||
Usage: "[DEPRECATED] Search Pandora via the speaker (no built-in equivalent yet)",
|
||||
Action: searchPandora,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
@@ -669,7 +710,7 @@ func main() {
|
||||
},
|
||||
{
|
||||
Name: "search-spotify",
|
||||
Usage: "Search Spotify content",
|
||||
Usage: "[DEPRECATED] Search Spotify via the speaker (no built-in equivalent yet)",
|
||||
Action: searchSpotify,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
@@ -686,19 +727,6 @@ func main() {
|
||||
},
|
||||
Before: RequireHost,
|
||||
},
|
||||
{
|
||||
Name: "search-radiobrowser",
|
||||
Usage: "Search Radio Browser stations via the AfterTouch service",
|
||||
Action: searchServiceRadioBrowser,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "query",
|
||||
Aliases: []string{"q"},
|
||||
Usage: "Search query",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "add",
|
||||
Usage: "Add station and play immediately",
|
||||
|
||||
Reference in New Issue
Block a user