Radio Browser Binding

Radio Browser is a community driven effort (like wikipedia) that aims to collect as many internet radio and TV stations as possible. With this binding you can use their API and database of stations to apply filters and find internet radio streams that interest you. Their is also a widget in the marketplace that will send the URL to a chromecast and make yourself a very powerful internet radio. If you’re sick of the same old advertisement on another streaming service, try this one out and get new content for a change. No subscriptions needed.

If you enjoy the binding, please consider sponsoring or a once off tip as a thank you via the links. This allows me to purchase software and hardware to contributing more bindings. Also some coffee to keep me coding faster never hurts :slight_smile:

Sponsor @Skinah on GitHub Sponsors

Paypal can also be used via
matt A-T pcmus D-O-T C-O-M

Website of Radio Browser

https://www.radio-browser.info/

Widget to match the binding

Changelog

Version 0.5

  • Bug fix: Reduce multiple stations and display search result count that matches list

Version 0.4

  • https used
  • recent list
  • More genres added including Reggae @sebSmarthome
  • Minor BREAKING CHANGE just needs the config updated to use comma separated values.

Version 0.3

  • Reconnect code added
  • Search station name and UUID ability added

Version 0.2

  • Limits number of stations that can be found to 1700 to keep cache below 2mb.
  • More genres added
  • Allows selecting all countries

Version 0.1

  • Initial Beta release
  • Working well but needs beta testers and have not added reconnect code yet. Waiting to see how popular this is before spending much time on it, so if you like it please give feedback.

Resources

http://pcmus.com/openhab/RadioBrowserBinding/org.openhab.binding.radiobrowser-4.2.0-SNAPSHOT.jar

JFOG JAR

You can download it from the openHAB owned server here, however due to how slow it is to serve the file, it can not be the source for marketplace installing.

https://openhab.jfrog.io/ui/native/libs-pullrequest-local/org/openhab/addons/bundles/org.openhab.binding.radiobrowser/4.2.0-SNAPSHOT/org.openhab.binding.radiobrowser-4.2.0-SNAPSHOT.jar

Source Code and Readme docs

6 Likes

If you use the widget you do not need to create any rules. If you want to use this and like me you do not want to use a tablet to browse and select a station, you can use a rule like the below, which is a single line to send the URL text across to the Chromecast (possibly others like squeezebox will work with the widget as well as this rule). Have not tried yet, but plan on looking to trigger popular stations via voice so if you have it working please post how to help even me on what is needed to do certain methods.

All that is needed is one single line in DSL script, it would be this…
LivingRoomSpeaker_PlayURI.sendCommand(Radio_Stream.state.toString)

The whole yaml to make this one line look more complex is…

configuration: {}
triggers:
  - id: "1"
    configuration:
      itemName: radio_Stream
    type: core.ItemStateChangeTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/vnd.openhab.dsl.rule
      script: >-
        LivingRoomSpeaker_PlayURI.sendCommand(Radio_Stream.state.toString)
    type: script.ScriptAction

Looking nice.
I’m using squeezebox and there is a stream url channel.
I’ll give it a try…
Greets

If I start the thing, I get an error.

This will be happening as your in a country with lots of stations that are hitting the max current capacity of the bindings/jetty buffers which appears to be 2MB.

I would change the show advanced config called filter to something like this as it will limit the stations to only the first 1700 that have a good click count. Anyone that downloads it from now on will have this change already done and wont need to make this change manually.

hidebroken=true,limit=1700,reverse=true,order=votes

This would show even less stations by removing any low quality streams below 192kbps (CD quality), but I would not do this, as you will throw away a lot of good stations as most will be at 128 and chat and sports ones probably lower.

EDIT: See readme file for examples that are up to date.

If you want to create your own custom filter, the options are listed here…

https://de1.api.radio-browser.info/#Advanced_station_search

So ok… With limit it is working… Limit 100 and sort by clicktrend is more than enough… :wink:
I have a few questions…
how to refresh the list? Just with thing pause / unpause?
and when I unpause the thing the country is Germany, that’s right… The language is ‘de’ and there are around 67 stations.
I have manually change the language channel to ‘german’ or ‘show all languages’ then there are much more stations.
Is there a ‘default’ language for my country? Or where is the ‘de’ comming? I would set it at show all languages or recall last state or something.
Greets

Recommend you uninstall and then reinstall it from the marketplace so you get the newer version that has your wish list plus more. Thanks for feedback and testing. It uses the country you have told openHAB your located in, now it defaults to all languages by default as the country should be enough.

Regarding refreshes you can do it the standard way the core recommends, by sending the REFRESH command. You can also do it with a pause and un-pause of the thing, which will update languages and countries, so the REFRESH is better as it only performs one call to do the station search again. It also will stops the filters getting cleared and reset.

On this topic please do not hammer their server updating it stupid amounts, it is a free server so keep it sensible, as the data probably rarely changes.

One area people testing can help out, is to work if there are certain codecs that stops the stream from starting to play on Chromecast and other devices. You can use the filter config to only use codecs you prefer, so look forward to seeing if people find any patterns on what works via the website, but not streaming to certain devices. We can then look to making changes in the appropriate bindings to gracefully handle a bad codec if problems are found.

Some of the stations use geolocation to block people not in their area, this is one reason why the binding defaults to using your country.

Thx, I updated to the marketplace version…
I’m using openhab since 2.4 but I’ve never heard about a refresh command :see_no_evil::grin::grin:
How do I send a refresh?
Greets

It has been around that whole time and it appears not to be documented unless you do development.

See the readme linked in the first post of this thread and I have added how to do searches with examples. These will not work till I release the next version after more testing first, but the refresh will work for you already. EDIT @Baschtlwaschtl just uploaded the newer jar that now has searches.

Also changed is that the filters config now has the following default as you need the reverse=true for the list to have the most popular at the top:

hidebroken=true,limit=1700,reverse=true,order=votes
2 Likes

[Update] 16/02/24
New version work with version 0.4
new refresh button
new search button
new recent button
Visibility of button

Thank you very much for your work
works very well

maybe add the reggae genre :wink:

I share my widget which I will have to improve with the new search possibility :smiley:


RadioBrower

uid: frs_RadioBrowser_Chromecast_list_item
tags:
  - multimedia
props:
  parameters:
    - default: Web Radio Chromecast
      description: Header Title
      label: Title
      name: WebRadioTitle
      required: false
      type: TEXT
    - default: iconify:material-symbols-light:radio
      description: Header Icon - Use f7:iconName (Framework7 icon), material:iconName (Material icon) or iconify:iconSet:iconName
      label: Icon
      name: WebRadioIcon
      required: false
      type: TEXT
    - context: item
      default: RadioBrowser
      description: Select the Radio Browser you wish to use at an equipment item level
      label: item
      name: radioBrowser
      required: true
      type: TEXT
      groupName: radiobrowser
    - context: item
      description: Select the Chromecast PlayURI item to send the radio URL.
      label: item
      name: playURI
      required: true
      type: TEXT
      groupName: chromecast
    - context: item
      description: Select the Chromecast Player Control Item
      label: item
      name: playerControlItem
      required: true
      type: TEXT
      groupName: chromecast
    - context: item
      description: Select the Chromecast Current time Item
      label: item
      name: currentTimeItem
      required: true
      type: TEXT
      groupName: chromecast
    - context: item
      description: Select the Chromecast Volume Control Item
      label: item
      name: volumeControlItem
      required: true
      type: TEXT
      groupName: chromecast
    - description: Enabled/Invisible Disabled/Visible
      label: Hide Country button
      name: HideCountryButton
      required: false
      type: BOOLEAN
      groupName: display
    - description: Enabled/Invisible Disabled/Visible
      label: Hide State button
      name: HideStateButton
      required: false
      type: BOOLEAN
      groupName: display
    - description: Enabled/Invisible Disabled/Visible
      label: Hide Language button
      name: HideLanguageButton
      required: false
      type: BOOLEAN
      groupName: display
    - description: Enabled/Invisible Disabled/Visible
      label: Hide Genre button
      name: HideGenreButton
      required: false
      type: BOOLEAN
      groupName: display
    - description: Enabled/Invisible Disabled/Visible
      label: Hide Recent button
      name: HideRecentButton
      required: false
      type: BOOLEAN
      groupName: display
    - description: Enabled/Invisible Disabled/Visible
      label: Hide Refreh button
      name: HideRefrehButton
      required: false
      type: BOOLEAN
      groupName: display
    - description: Enabled/Invisible Disabled/Visible
      label: Hide Search button
      name: HideSearchButton
      required: false
      type: BOOLEAN
      groupName: display
  parameterGroups:
    - name: radiobrowser
      label: Radio Browser binding
    - name: chromecast
      label: Chromecast binding
    - name: display
      label: Display
timestamp: Feb 16, 2024, 7:07:25 PM
component: oh-list-card
config:
  accordionList: true
  colorTheme: gray
slots:
  default:
    - component: oh-list-item
      config:
        accordionItemOpened: false
        accordionList: true
        icon: =props.WebRadioIcon
        mediaList: false
        title: =props.WebRadioTitle
      slots:
        accordion:
          - component: f7-list
            config:
              style:
                background-color: "=themeOptions.dark === 'dark' ? 'rgb(35, 35, 35)' : 'rgb(247, 247, 247)'"
            slots:
              default:
                - component: f7-row
                  config:
                    class:
                      - display-flex
                      - justify-content-center
                    style:
                      margin-left: 6px
                      margin-right: 6px
                      padding-top: 14px
                  slots:
                    default:
                      - component: oh-button
                        config:
                          visible: =!props.HideCountryButton
                          action: options
                          actionItem: =props.radioBrowser+'_Country'
                          iconF7: globe
                          iconSize: 22
                          outline: false
                          raised: true
                          round: false
                          small: true
                          style:
                            --f7-button-bg-color: "=themeOptions.dark === 'dark' ? 'rgba(55, 55, 55, 0.6)' : 'rgba(215, 215, 215, 0.6)'"
                            height: 28px
                            margin-bottom: 6px
                            margin-left: 3px
                            margin-right: 3px
                          text: =items[props.radioBrowser+'_Country'].state
                      - component: oh-button
                        config:
                          visible: =!props.HideStateButton
                          action: options
                          actionItem: =props.radioBrowser+'_State'
                          iconF7: rectangle_3_offgrid
                          iconSize: 22
                          outline: false
                          raised: true
                          round: false
                          small: true
                          style:
                            --f7-button-bg-color: "=themeOptions.dark === 'dark' ? 'rgba(55, 55, 55, 0.6)' : 'rgba(215, 215, 215, 0.6)'"
                            height: 28px
                            margin-bottom: 6px
                            margin-left: 3px
                            margin-right: 3px
                          text: =items[props.radioBrowser+'_State'].state
                      - component: oh-button
                        config:
                          visible: =!props.HideLanguageButton
                          action: options
                          actionItem: =props.radioBrowser+'_Language'
                          iconF7: chat_bubble_text
                          iconSize: 22
                          outline: false
                          raised: true
                          round: false
                          small: true
                          style:
                            --f7-button-bg-color: "=themeOptions.dark === 'dark' ? 'rgba(55, 55, 55, 0.6)' : 'rgba(215, 215, 215, 0.6)'"
                            height: 28px
                            margin-bottom: 6px
                            margin-left: 3px
                            margin-right: 3px
                          text: =items[props.radioBrowser+'_Language'].state
                      - component: oh-button
                        config:
                          visible: =!props.HideGenreButton
                          action: options
                          actionItem: =props.radioBrowser+'_Genre'
                          iconF7: music_note_list
                          iconSize: 22
                          outline: false
                          raised: true
                          round: false
                          small: true
                          style:
                            --f7-button-bg-color: "=themeOptions.dark === 'dark' ? 'rgba(55, 55, 55, 0.6)' : 'rgba(215, 215, 215, 0.6)'"
                            height: 28px
                            margin-bottom: 6px
                            margin-left: 3px
                            margin-right: 3px
                          text: =items[props.radioBrowser+'_Genre'].state
                - component: f7-row
                  config:
                    class:
                      - display-flex
                      - justify-content-center
                    style:
                      margin-left: 6px
                      margin-right: 6px
                      margin-bottom: -6px
                      padding-top: 3px
                  slots:
                    default:
                      - component: oh-button
                        config:
                          visible: =!props.HideRecentButton
                          action: options
                          actionItem: =props.radioBrowser+'_Recent'
                          iconF7: music_albums
                          iconSize: 22
                          outline: false
                          raised: true
                          round: false
                          small: true
                          style:
                            --f7-button-bg-color: "=themeOptions.dark === 'dark' ? 'rgba(55, 55, 55, 0.6)' : 'rgba(215, 215, 215, 0.6)'"
                            height: 28px
                            margin-bottom: 6px
                            margin-left: 3px
                            margin-right: 3px
                      - component: oh-button
                        config:
                          visible: =!props.HideRefrehButton
                          action: command
                          actionCommand: REFRESH
                          actionItem: =props.radioBrowser+'_Station'
                          iconF7: arrow_2_circlepath
                          iconSize: 22
                          outline: false
                          raised: true
                          round: false
                          small: true
                          style:
                            --f7-button-bg-color: "=themeOptions.dark === 'dark' ? 'rgba(55, 55, 55, 0.6)' : 'rgba(215, 215, 215, 0.6)'"
                            height: 28px
                            margin-bottom: 6px
                            margin-left: 3px
                            margin-right: 3px
                      - component: oh-button
                        config:
                          visible: =!props.HideSearchButton
                          action: variable
                          actionVariable: showSearch
                          actionVariableValue: =!(vars.showSearch === true)
                          iconF7: search
                          iconSize: 22
                          iconColor: "=(vars.showSearch) ? 'blue' : 'gray'"
                          outline: false
                          raised: true
                          round: false
                          small: true
                          style:
                            --f7-button-bg-color: "=themeOptions.dark === 'dark' ? 'rgba(55, 55, 55, 0.6)' : 'rgba(215, 215, 215, 0.6)'"
                            height: 28px
                            margin-bottom: 6px
                            margin-left: 3px
                            margin-right: 3px
                - component: f7-block
                  config:
                    style:
                      margin-left: 0px
                      margin-right: 0px
                      margin-top: 14px
                  slots:
                    default:
                      - component: oh-input
                        config:
                          visible: =vars.showSearch === true
                          outline: true
                          clearButton: true
                          sendButton: true
                          inputmode: text
                          item: =props.radioBrowser+'_Station'
                          placeholder: =items[props.radioBrowser+'_Station'].state
                          type: text
                          style:
                            --f7-cols-per-row: 1.16
                - component: f7-row
                  config:
                    class:
                      - align-items-center
                      - display-flex
                      - justify-content-space-between
                    style:
                      margin-top: 14px
                      margin-left: 18px
                      margin-right: 18px
                      flex-wrap: nowrap
                  slots:
                    default:
                      - component: oh-image
                        config:
                          item: =props.radioBrowser+'_Icon'
                          style:
                            height: 44px
                            border-radius: 6px
                      - component: oh-button
                        config:
                          action: options
                          actionItem: =props.radioBrowser+'_Station'
                          outline: false
                          raised: true
                          round: false
                          large: true
                          style:
                            --f7-button-bg-color: "=themeOptions.dark === 'dark' ? 'rgba(55, 55, 55, 0.6)' : 'rgba(215, 215, 215, 0.6)'"
                          text: =items[props.radioBrowser+'_Name'].state
                      - component: oh-link
                        config:
                          action: command
                          actionCommand: =items[props.radioBrowser+'_Stream'].state
                          actionItem: =props.playURI
                          iconF7: plus_circle_fill
                          style:
                            width: 44px
                            justify-content: flex-end
                - component: f7-row
                  config:
                    class:
                      - align-items-center
                      - display-flex
                      - justify-content-space-between
                    style:
                      padding-bottom: 14px
                      margin-left: 18px
                      margin-right: 18px
                      margin-top: 14px
                      flex-wrap: nowrap
                  slots:
                    default:
                      - component: oh-link
                        config:
                          action: variable
                          actionVariable: showVolume
                          actionVariableValue: =!(vars.showVolume === true)
                          color: "=(vars.showVolume) ? 'blue' : 'gray'"
                          iconF7: '=(Number.parseInt(items[props.volumeControlItem].state) >= 75) ? "speaker_3_fill" : (Number.parseInt(items[props.volumeControlItem].state) > 50) ? "speaker_2_fill" : (Number.parseInt(items[props.volumeControlItem].state) > 10) ? "speaker_1_fill" : (Number.parseInt(items[props.volumeControlItem].state) > 0) ? "speaker_fill" : (Number.parseInt(items[props.volumeControlItem].state) == 0) ? "speaker_slash_fill" :"speaker_slash_fill"'
                          iconSize: 36
                          round: true
                      - component: oh-player-controls
                        config:
                          showRewindFFward: false
                          item: =props.playerControlItem
                          visible: =!vars.showVolume
                      - component: oh-slider
                        config:
                          color: blue
                          item: =props.volumeControlItem
                          style:
                            margin-top: 14px
                            margin-bottom: 10px
                            width: 62%
                          visible: =vars.showVolume === true
                      - component: Label
                        config:
                          style:
                            color: gray
                            font-size: 20px
                            font-weight: 500
                          text: "=items[props.currentTimeItem].state == 'UNDEF' ? '00:00' : dayjs().startOf('day').add(items[props.currentTimeItem].state.split(' ')[0], 'seconds').format(items[props.currentTimeItem].state.split(' ')[0] < 3600 ? 'mm:ss' : 'H:mm:ss')"

2 Likes

Thanks for creating a better widget, I look forward to trying it out.

The state of the station channel will tell you how many search results came back, the widget can use this if you wish.

Look forward to seeing what you come up with. At this point the binding is still beta and not merged, so if it makes sense to change something now to make widget and the use in rules easier, please make a suggestion.

error with the reggae genre

2024-02-16 17:01:18.475 [WARN ] [browser.internal.api.RadioBrowserApi] - IllegalArgumentException:Illegal character in query at index 133: https://nl1.api.radio-browser.info/json/stations/search?hidebroken=true&limit=1700&reverse=true&order=votes&countrycode=FR&tag=reggae

error : search with “france inter”
no error: search with “france%20inter”

2024-02-16 17:03:26.921 [WARN ] [browser.internal.api.RadioBrowserApi] - IllegalArgumentException:Illegal character in path at index 62: https://nl1.api.radio-browser.info/json/stations/byname/france inter

recent list :+1: thanks
I updated my previous post with a new widget version

Fixed your two reported bugs and uploaded the jar. Thanks…
Any more bugs found please report as its getting reviewed to be merged and would be good to have it as close to bug free from the first release.

thanks, now it works :+1:

search with “france info”
count 2 stations but display 10 stations
no error in log

Searches are done without any other active filters when done via name or UUID.

If you do a search giving an exact UUID then it would confuse users if it did not start playing when an exact ID is given.

My guess is its correct when you look world wide and all languages etc…

EDIT:

I looked and found the reason, you get 10 results but they are all named the same except 1 which has a name with lofi added. The code counts the names and gives 2 but adds all the results as options.

This link shows the results in json.
https://de1.api.radio-browser.info/json/stations/byname/France%20Info

@sebSmarthome
A fix is now uploaded and will only use the first result of an exact station name, so which one of the mutliples will be used will be based on the votes, if you use the defaults of the binding. Because stations are in the database multiple times this will now reduce the results. The database server actually checks that the stations stream is not broken every day, so in theory this should work fine.

good idea, I just tested it, perfect :+1: Thanks a lot