Skip to content

Instantly share code, notes, and snippets.

@rody64
Last active May 29, 2026 09:38
Show Gist options
  • Select an option

  • Save rody64/98a59990ff60ea962cac72cbe93edf56 to your computer and use it in GitHub Desktop.

Select an option

Save rody64/98a59990ff60ea962cac72cbe93edf56 to your computer and use it in GitHub Desktop.
A comprehensive guide to a possible solution for streaming internet radio to Bose SoundTouch speakers via local UPnP (Gerbera) and configure presets using Home Assistant, Python API, or WebServices after Bose's cloud service EOL in Feb 2026.

🎵 Play Internet Radio on Bose SoundTouch After Cloud Shutdown (Feb 2026)

This setup should allow your Bose SoundTouch speakers to continue playing Internet radio locally after Bose discontinues its cloud services (February 2026).
This method is experimental until confirmed after the official EOL.

It replaces the soon-to-be-retired TuneIn integration while keeping local playback working.

Note: Based on recent community testing, SoundTouch presets will likely stop working after the Bose cloud shutdown in February–March 2026 unless a workaround is found.

08-12-2025 — Removed most of this Gist because there’s a much simpler solution than using the Gerbera media server: hosting a JSON description of the radio station on an HTTP server (thanks to user gmuth).
19-11-2025 — Added testing notes:
thlucas1/homeassistantcomponent_soundtouchplus#37 (comment)


🧪 Preliminary Conclusion

Testing strongly indicates that even for “local” services like UPnP (STORED_MUSIC), Bose SoundTouch devices still rely heavily on the Bose cloud for initial setup and for enabling/persisting certain features.

This means that once the Bose cloud services are truly shut down, it is highly likely that:

  • Factory-reset devices will not be able to register new UPnP or other music services via the API or the app.
  • Existing configurations may disappear, especially presets, if the device attempts to “re-authenticate” or periodically sync with the now-absent cloud.

This reinforces the need to have SoundTouch devices fully configured and cloud-registered before the EOL date, hoping that existing configurations will continue to work for local playback afterward.

Possible directions for long-term solutions

  • Reverse-engineering the cloud interaction and simulating the required responses locally
  • Using an external device on AUX IN (e.g., a streamer or Raspberry Pi) to provide radio and other sources independent of the SoundTouch cloud

📡 Using JSON to Store a Radio Station

You can host a JSON description of the radio station on any HTTP server, e.g. bbc1.json.

Create a file such as bbc1.json containing:

{
  "audio": {
    "hasPlaylist": false,
    "isRealtime": true,
    "streamUrl": "http://bbc.com/stream/..."
  },
  "imageUrl": "",
  "name": "BBC 1",
  "streamType": "liveRadio"
}

Place this file on your HTTP server.

Now store the station to preset 1 using:

curl -d @- http://soundtouch:8090/storePreset << XML
<preset id="1">
  <ContentItem source="LOCAL_INTERNET_RADIO" type="stationurl" location="http://yourserver/bbc1.json">
    <itemName>BBC 1</itemName>
  </ContentItem>
</preset>
XML

📝 Notes

  • Stream URLs must use HTTP, not HTTPS.
  • Sometimes the SoundTouch does not start the preset immediately — a reboot usually fixes it.
  • This method remains experimental until confirmed after the SoundTouch cloud EOL in February 2026.
  • Also check out soundcork, which aims to intercept SoundTouch API calls and may offer a long-term solution:
    https://github.com/deborahgu/soundcork
@phfuh

phfuh commented Feb 8, 2026

Copy link
Copy Markdown

@gmuth thanks for the quick feedback. Blocking content.api.bose.io completely crashes the app, but using the presets on the device and the streams works fine. Also, blocking streaming.bose.com and events.api.bosecm.com doesn’t break presets or streams.

The idea of my list is to simplify the process for the end user. Making an API call is already complicated enough for a normal user.

For myself, I have an n8n workflow that generates a JSON file based on data from Radio Browser.

@phfuh

phfuh commented Feb 8, 2026

Copy link
Copy Markdown

Device reboot is working, but power disconnect is not. After a power disconnect, you need to unblock content.api.bose.io once.

After a power disconnect, the box checks content.api.bose.io every minute until unblocked. In the blocked state, the box is reachable over the API and the presets are still present. It seems to me that the call to content.api.bose.io is only a connectivity check.

@bilboo9696

Copy link
Copy Markdown

Hi there,

sorry for maybe asking a silly question but new to this all here.

Where exactly do you run the curl command with the xml instructions from to set the preset keys with the .json fiel on the http web server..... can you run it from a command prompt on windows?

tnx a mil

@phfuh

phfuh commented Feb 20, 2026

Copy link
Copy Markdown

The simplest way is to use Insomnia, Postman, or something similar to send your requests as i wrote in my repository mentioned above.

On Windows, you can also try using Invoke-WebRequest in PowerShell. It should look something like this:

$url = "https://example.com/api"

$xmlBody = @"
<?xml version="1.0" encoding="UTF-8"?>
<Request>
    <Name>John Doe</Name>
    <Email>john.doe@example.com</Email>
</Request>
"@

Invoke-WebRequest `
    -Uri $url `
    -Method Post `
    -Body $xmlBody `
    -ContentType "application/xml"

@sdenengelsman

Copy link
Copy Markdown

I still can't believe Bose is doing this...
I can't help coding (stopped with coding some time ago) but am happy to try things every now and then. I have several Soundtouch Wireless Link devices and a Soundtouch 20, which I hope will all keep working as I use them on a regular basis, especially the Spotify streaming feature.
I'll keep an eye on the messages here :-)

@timvahlbrock

Copy link
Copy Markdown

@phfuh, it's kind of brute force but you could convert the entire radio station database from radio-browser.info (available in one big json list) into single json files using the bose json format.

Wouldn't it be even nicer, to create a proxy application (or maybe even contribute it to radio-browser.info) that is able to just convert the information radio-browser.info already provides into the required format?

Source type LOCAL_INTERNET_RADIO will stop working in May. You can verify by denying the device access to bose cloud servers (e.g. by using a blacklist filter of your router).

Is there any source that this will definitely be the case? Did Bose want to provide one more update before may? Maybe this update will allow using LOCAL_INTERNET_RADIO without the Bose Soundtouch servers?

@timvahlbrock

Copy link
Copy Markdown

Is there any source that this will definitely be the case?

Seems like this is still unclear, at least Bose support gave me conflicting information/couldn't help me with that. If the update in may fixes that, switching existing presets to LOCAL_INTERNET_RADIO would be the best option in my point of view. Though some other thread indicate that without adjustments in the update presets will survive reboots without the Bose servers.

@gmuth

gmuth commented Mar 9, 2026

Copy link
Copy Markdown

I tried UPNP and QPLAY - so this might indeed provide a solution to play radio streams without requiring the user to gain root access.
SoundTouch provides multiple options: UPNP, QPLAY and STORED_MUSIC. We still need a Client App that can be used to start the stream (like mconnect). @rody64, could you document how to setup a UPNP stream - maybe with a simple docker setup? My router supports this feature so I can see:

<nowPlaying deviceID="..." source="UPNP" sourceAccount="UPnPUserName">
  <ContentItem source="UPNP" location="http://192.168.2.1:49200/ST/AUDIO/DLNA-1-0/dispatcher.rndfnk.com/br/br3/live/mp3/mid" 
sourceAccount="UPnPUserName" isPresetable="false">

@dirkdesmet

dirkdesmet commented May 7, 2026

Copy link
Copy Markdown

Okay, today it happened: the presets are not working anymore.

Some of my observations:

I started overwriting the presets by posting the preset XML to http://ip-of-the-radio:8090/storePreset ... and it still does not work, even after a radio reboot.

I have the Bose Soundtouch 20 directly connected with an UTP cable and when creating a POST, I do see the presets list (http://ip-of-the-radio:8090/presets) updating with the new values.

Example xml body that I post:

<preset id="6">
    <ContentItem source="LOCAL_INTERNET_RADIO" type="stationurl" location="http://ip-of-my-laptop:8080/radio2.json">
        <itemName>Radio 2</itemName>
    </ContentItem>
</preset>

However, the URL provided in the the location attribute does never get called in my test setup.

Simple python http server to play with:

python -m http.server 8080

The only thing that I see working directly on the radio is the value of <itemName>Radio 2</itemName>.
But the location url (the json file) is never called. Not when pressing the preset button, not after reboot, never.

It feels like there goes something wrong with the location XML attribute; I think that the value we are providing is getting concatenated to some baseUrl or something, which causes that the json file never gets requested by the radio.

P.S.:
The updated preset does survive a reboot; the changes remain in it's memory.

@gmuth

gmuth commented May 7, 2026

Copy link
Copy Markdown

This GIST does not provide a full solution for playing radiostreams. It only explains the last step where the response provides the stream url to be used by the device. Device and music provider setup are not covered here but are also required.

@phfuh

phfuh commented May 7, 2026

Copy link
Copy Markdown

Wouldn't it be even nicer, to create a proxy application (or maybe even contribute it to radio-browser.info) that is able to just convert the information radio-browser.info already provides into the required format?

Done. I also created a small UI to generate the XML POST body or send it directly:
https://phfu.codeberg.page/soundtouch-preset-manager/

@gmuth

gmuth commented May 7, 2026

Copy link
Copy Markdown

@phfuh, the cloudfare worker is really cool! - Is the source available?
For tunein a id-to-url-resolver cloudflare worker could solve potential rate limit issues I had when using a cloud server.
Radio-Browser also supports the Bose SoundTouch format:
https://all.api.radio-browser.info/soundtouch/stations/byuuid/960e57c5-0601-11e8-ae97-52543be04c81
It doesn't matter if you use this api with a RADIO_BROWSER source or a LOCAL_INTERNET_RADIO source. The latter supports absolute location urls (instead of having the baseUrl of the source appended by the location attribute of the content item).

@dirkdesmet

Copy link
Copy Markdown

This GIST does not provide a full solution for playing radiostreams. It only explains the last step where the response provides the stream url to be used by the device. Device and music provider setup are not covered here but are also required.

Okay, I understand - thanks!

I went for the soundcork solution and re-programmed the preset buttons; now my Bose Soundtouch 20 is working again.

@Olivier822

Copy link
Copy Markdown

@phfuh I tried your solution today but it's not working. During my tests I noticed that when I use an url like https, it's not working. My problem is that I'm not good in code. I don't have a easy way to solve this problem after the Bose cloud shut down.
@dirkdesmet Could you say to me which part of soundcork solution have you change. I can make by myself the little changes but I'm lost.

Thanks.

@gmuth

gmuth commented May 9, 2026

Copy link
Copy Markdown

I guess I have to build and document a minimal solution for playing custom radio streams. In order to select the radio-json you don't need soundcork or any other cloud replacement. Only one bmx API is required - and the response can even be static served from any shared webspace. You will need to install the Postman application and get familiar with the Soundtouch API ie by using my soundtouch collection

@musnuxer

musnuxer commented May 9, 2026

Copy link
Copy Markdown

I guess I have to build and document a minimal solution for playing custom radio streams. In order to select the radio-json you don't need soundcork or any other cloud replacement. Only one bmx API is required - and the response can even be static served from any shared webspace. You will need to install the Postman application and get familiar with the Soundtouch API ie by using my soundtouch collection

Yes "minimal solution" is a good term.
I would be really excited to see a minimal solution that can run onboard on the Bose Soundtouch without the need of any additional hardware/server...
In theory it shouldn't be that big of a deal?
Probably somebody can make some fancy tool where one can set the presets over a small webinterface running on the box.
I guess there are many people out there who only need that basic functionality to be able to assign specific radio stations to the presets and play them, not more. Any other playback content can always be played ober AirPlay or Bluetooth.

@Olivier822

Copy link
Copy Markdown

@phfuh Thanks for your UI.
I made the test with your small UI. It completly works on my Bose Wave soundtouch but not on my Bose Soundtouch 20.
On my soundtouch 20, I saw the change of name but the sound is not working (error message on the soundtouch 20).
Any ideas?

Thanks by advance

@dirkdesmet

dirkdesmet commented May 9, 2026

Copy link
Copy Markdown

@Olivier822

@phfuh I tried your solution today but it's not working. During my tests I noticed that when I use an url like https, it's not working. My problem is that I'm not good in code. I don't have a easy way to solve this problem after the Bose cloud shut down.

You really need to use http instead of https...

@dirkdesmet Could you say to me which part of soundcork solution have you change. I can make by myself the little changes but I'm lost.

Thanks.

Well, since you're not that much into coding, I'll share you the exact steps I did to get it working on my Bose Soundtouch radio .

Notice that I already have several microservices running in Docker at my home server, so I had the hard- and software already available to quickly deploy another microservice (Soundcork) which can be persistent over there for as long as needed.
In my case this is on a Debian (Linux) environment; but you can certainly get similar results on other platforms as well.

I played a bit around with Soundcork and if the server is not running, I cannot start any of the presets of my Bose system. So the Soundcork service (or similar) seems to be a hard requirement at first sight.

Preparing a server for running Soundcork in a Docker container

If you decided where you're going to run (and keep) this server, use a terminal and enter these commands below to prepare your server with the required tools before we install Soundcork.
It could be that you can skip some steps, because some tools might already be installed; in that case just continue to the next step.

The first part is mainly focused on installing Docker, I'll be as transparent as possible so that you understand what you are doing in each step.

  1. sudo apt update && sudo apt install curl ca-certificates
    With this chained command above, we're doing 3 things at once:

    • apt update => updating your servers local indexes of available packages from the repositories
    • curl => a tool that in this case will help us downloading a key for the Docker repository
    • ca-certificates => to be able to add the the Docker repository, it allows your server to verify SSL/TLS (https) sources
  2. sudo install -m 0755 -d /etc/apt/keyrings
    This command creates a directory and sets the right permissions to work with it; we'll be adding the required keys for the Docker repo over there in the next step.

  3. curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
    We downloaded the GPG key from Docker.

  4. chmod a+r /etc/apt/keyrings/docker.asc
    We're making sure that all users on your server can read this key.

  5. sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
    Types: deb
    URIs: https://download.docker.com/linux/debian
    Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
    Components: stable
    Architectures: $(dpkg --print-architecture)
    Signed-By: /etc/apt/keyrings/docker.asc
    EOF

    You have to copy this whole block at once, do not execute it line by line.
    This part adds the Docker repo to you server, it makes sure we can install everything we need to get Docker running.

  6. sudo apt update && sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin git
    We're installing several things at once again:

    • docker-ce => Docker Community Edition, the Docker "engine"
    • docker-ce-cli => Docker command line interface
    • containerd.io => It helps managing Docker containers (starting, stopping, ...)
    • docker-buildx-plugin => Tool for building Docker images
    • docker-compose-plugin => Tool for installing and configuring things instructed in yml files; this will make installing Soundcork really easy
    • GIT => to be able to clone the source code from soundcork

Installing Soundcork

At the time of writing, the Soundcork developer did not document this way of installing Soundcork, but this is exactly how I did it, because I spotted the docker-compose.yml file, which makes installing things really easy. You can follow these steps or adapt to your needs, I'm just reporting 1:1 what I did to get my radio presets working again.

  1. cd /opt/
    This is the place where I wanted to install soundcork.
  2. git clone https://github.com/deborahgu/soundcork.git
    We're getting a copy of the Soundcork source code on your own server; it creates a new directory "soundcork" inside the /opt/ directory and puts the source code over there. (/opt/soundcork)
  3. cd soundcork && ls -al
    We're first navigating to the soundcork folder and ask to display a detailed list structure
  4. vi docker-compose.yml (this can also be nano docker-compose.yml, whichever file editor floats your boat is fine.)
    I edited a few personal things, but this might be different for you:
    • I changed this line: base_url=http://<ip_of_your_server_here>:8001 (but you can leave it like it original was, I have static IP's so that's my preferred way of pointing to servers)
    • I Also added this line in the "volumes:" section, because I wanted Soundcork to also host my radio station json / png files: /root/bosePresets/:/app/soundcork/static/bosePresets => on my host system, I have a /root/bosePresets/ folder containing these radio station files. We're simply passing that folder through at the Docker instance, right at a place where we can easily access the files from the radio.
  5. Save your changes
  6. mkdir -p /root/bosePresets => this creates a bosePresets folder in your host's /root folder, so that managing radio stations is a bit more easy. (I couldn't find in Soundcork how to edit these radio presets, so I did it manually with the curl command instead.)
  7. docker compose up => This finally creates and launches the soundCork server, it will be available in your browser at http://<ip_of_your_server>:8000/
  8. I can't replicate this step anymore, but from what I remember, I just visited that link in my browser and it detected my Bose Soundtouch radio and I could click on a button "Add to Soundcork" (Oh yes: first make ssh access available on your radio by preparing a USB stick with an empty file called "remote_services" on it. No content, just exactly that name without any file extension. Plug it in your radio and reboot the radio.)

Adding new radio presets

In the previous section we prepared a folder /root/bosePresets on the host system (outside Docker), we're going to make use of this now to add the new radio presets.

  1. cd /root/bosePresets
  2. touch radio1.json radio2.json topradio.json some_other_radio.json yet_another_radio.json and_another_radio.json
    This makes 6 json files which all will be pointing to the radio streams that we want to bind to the radio preset buttons.
  3. vi radio1.json (and later on all the other json files too)
    Edit the radio preset file and paste the following content (don't forget to put your own streamUrl value to your preferred radio station over there + only use http links, no https.)
    {
      "audio": {
        "hasPlaylist": true,
        "isRealtime": true,
        "streamUrl": "http://icecast.vrtcdn.be/radio1.aac"
      },
      "name": "Radio 1",
      "streamType": "liveRadio"
    }
  4.  curl -d @- http://192.168.1.163:8090/storePreset << XML
     <preset id="1">
       <ContentItem source="LOCAL_INTERNET_RADIO" type="stationurl" location="http://<ip_of_your_server_here>:8000/static/bosePresets/radio1.json">
         <itemName>Radio 1</itemName>
       </ContentItem>
     </preset>
     XML
    Again, copy the whole block and execute it, this links the radio1.json content to preset button #1 on your radio.
    / ! \ Don't forget to replace <ip_of_your_server_here> first and also keep in mind that <preset id="1"> means button #1.
  5. Now press that preset button on your radio and you should start hearing music.
  6. Repeat this for all desired preset buttons, to assign new streaming URL's and keep in mind that the Soundcork service must be active for the preset buttons to work.

Sources

For now, this lengthy solution is fine for me, although I do hope to find a better more "minimal" solution without server. I was thinking about maybe running a simple script on the radio since it's also using linux as its operating system, but I didn't find the time yet to further investigate this.

@musnuxer

musnuxer commented May 9, 2026

Copy link
Copy Markdown

@phfuh @Olivier822
The phfuh UI is doing its job > it is modifying the presets.
But the problem: LOCAL_INTERNET_RADIO service needs to connect to a server > either Bose (all are shut down!) or a local solution (soundcork, opencloudtouch, ....). So phfuh UI alone isn't helping at all...

So again, I am voting for the dev of a basic onboard-solution that is integrated on the Soundtouch system.
Assigning Radio-Stations to presets and beeing able to play them, this is the only thing I would need for instance...

@timvahlbrock

Copy link
Copy Markdown

I would be really excited to see a minimal solution that can run onboard on the Bose Soundtouch without the need of any additional hardware/server...

@musnuxer I migrated five devices with very little effort with very little effort using gesellix's soundtouch-service. I still have two networks from relatives that I don't want to host a server in, so we started creating a guide on how to run this service on the device with a single command installer, which is currently being reviewed.

Disclaimer: We had a discussion with @gmuth in the last days on the 'minimalisim' of this solution, because the soundtouch-service is capable of more than just serving the presets. Though because this was the fastest way we could get this to work was to use the existing binaries including all the features, we decided to stick with this for now. Even though the service already consumes next to nothing resources already, further optimization, improvements and fixes will come in the next weeks.

@musnuxer

musnuxer commented May 9, 2026

Copy link
Copy Markdown

@timvahlbrock
yes cool!!! That's what I am looking for...
Any chance to get the script already "kind of beta testing"?

@Olivier822

Copy link
Copy Markdown

@dirkdesmet Thank you. The beginning seems not working on my Window's laptop. I will try tomorrow on another laptop with Ubuntu.

@timvahlbrock

Copy link
Copy Markdown

@timvahlbrock yes cool!!! That's what I am looking for... Any chance to get the script already "kind of beta testing"?

Yeah, the variables in the installer script can be overridden. Before you run the install command (rw && curl ....) run

export VERSION=0.72.2
export INIT_SCRIPT_URL="https://raw.githubusercontent.com/timvahlbrock/Bose-SoundTouch/feat/on-device-install/scripts/on-device-install/aftertouch"

The version needs to be overwritten because the install script already points to the next release and the init script url needs to be overwritten because the init script is not in the base repo yet.

@phfuh

phfuh commented May 9, 2026

Copy link
Copy Markdown

@gmuth

@phfuh, the cloudfare worker is really cool! - Is the source available? For tunein a id-to-url-resolver cloudflare worker could solve potential rate limit issues I had when using a cloud server. Radio-Browser also supports the Bose SoundTouch format: https://all.api.radio-browser.info/soundtouch/stations/byuuid/960e57c5-0601-11e8-ae97-52543be04c81 It doesn't matter if you use this api with a RADIO_BROWSER source or a LOCAL_INTERNET_RADIO source. The latter supports absolute location urls (instead of having the baseUrl of the source appended by the location attribute of the content item).

Oh cool, I don't recognize that. Because of this, my Cloudflare Worker is now obsolete. I'm changing my UI to the RadioBrowser API. The Worker's source code is now available in the repository. Hopefully it helps you.

@gmuth

gmuth commented May 9, 2026

Copy link
Copy Markdown

@phfuh @Olivier822 The phfuh UI is doing its job > it is modifying the presets. But the problem: LOCAL_INTERNET_RADIO service needs to connect to a server > either Bose (all are shut down!) or a local solution (soundcork, opencloudtouch, ....). So phfuh UI alone isn't helping at all...

So again, I am voting for the dev of a basic onboard-solution that is integrated on the Soundtouch system. Assigning Radio-Stations to presets and beeing able to play them, this is the only thing I would need for instance...

Have a look at SoundPloy V1

@musnuxer

musnuxer commented May 9, 2026

Copy link
Copy Markdown

@timvahlbrock
have tried with 0.72.0 (did not find 0.72.2 anywhere) on an ST10 > but have not been successful because the ST10 is struggling with disk space!

@gmuth
yes, cool and simple! That is the very basic I am looking for.

@timvahlbrock

Copy link
Copy Markdown

@timvahlbrock
have tried with 0.72.0 (did not find 0.72.2 anywhere) on an ST10 > but have not been successful because the ST10 is struggling with disk space!

Okay, thanks for letting me know.

@ebanfr-cell

Copy link
Copy Markdown

@phfuh Hey there ! tried to use your software and the web interface aswell, but unfortunately i'm unable to play anything. The presets seem to be saved on the device as i can see them by visiting http://SPEAKERIP:8090/presets , but when I press the preset button on the remote the speakers says "preset 1 empty". Any idea ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment