CLI tool
coderholic/pyradio avatar
coderholic/pyradio

PyRadio: a curses radio player that hands the audio to mpv, mplayer or VLC

Curses based internet radio player

1,099 stars133 forksPythonMIT

At a glance

What is it?
PyRadio is a terminal internet radio player for Linux, macOS and Windows that uses curses for its interface and an external player for the sound, with RadioBrowser, themes, station registers, a remote control server and OS media key support. The maintainer asks you to install it from your distribution or build it from source, and explicitly not from pip, Snap or AppImage.
Who is it for?
Adopt PyRadio if you want internet radio in a terminal, you already have a local player such as mpv or VLC, and you like a vi-like interface with a searchable station list and the RadioBrowser directory. Do not adopt it if you need a packaged, dependency-free binary on every machine, if you are on a platform without curses or without a supported player, or if you want a graphical interface.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 169 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A curses front end that hands audio to an external player

PyRadio is a command line internet radio player. The interface is built with curses, so it draws a station list in a terminal, and the audio itself is produced by a separate program. The requirements are explicit that MPV, MPlayer or VLC must be installed and on your path.

That division is the design, and it is a sensible one for a terminal application. The curses layer handles the list, the search, the theme and the configuration, while the player binary handles decoding and, if you want, the audio device. You get the familiar MPV or VLC behaviour for the sound, and a fast, dependency-light interface for the browsing.

It also means PyRadio is not a self-contained media player. If none of the three players is installed, there is no sound, and there is no fallback included in the project. The optional extras in the packaging metadata make this explicit, with a `cli` extra that lists `mpv`, `mplayer` and `vlc` as optional dependencies you can request at install time.

The intended user is someone who lives in a terminal. The feature list is written for that person: vi-like keys alongside the arrow and special keys, a station register that behaves like vi's registers, a configuration editor, a station editor, customisable key bindings, playlist validation, and a search function. It runs on Linux, macOS and Windows, and the packaging metadata classifies it as operating system independent with Python 3 as the only language.

The current version string is 0.9.3.11.31.

Running it: pyradio, then a handful of keys

After a successful installation, the command to run is simply:

bash
pyradio

That opens the window with the list of predefined stations. The interaction model is short enough to learn in a minute. You move with the arrow keys and press ENTER to start playback. The `+` key, or `.`, raises the volume and `-`, or `,`, lowers it, and `v` saves the volume. The `?` key opens the help screens and `\h` opens the HTML help pages. `Esc` or `q` exits.

Two of those keys lead to most of the functionality. Pressing `t` lists the themes, the right arrow activates the selected theme, and space makes that theme the default. The theme documentation covers how to write your own, which is the kind of thing a curses application can offer that a web player cannot, since the interface is just a set of text attributes and colours.

The other is capital `O`, which opens the RadioBrowser online directory. The README is candid that this interface needs its own page of documentation, and links to `docs/radio-browser.md` for how to navigate it. RadioBrowser support was added in version 0.9.0, and it is the feature that turns PyRadio from a fixed list of stations into a directory of whatever the community has published.

Beyond that, the detailed documentation lives in `docs/index.md`, and the README makes the point that this is where the numerous features are described. The M3U playlist support has its own page, as do the OS media controls and the RadioBrowser guide.

Install from your distribution, or build it, but not from pip

The installation guidance is unusually opinionated, and the reason is given plainly.

The best route is a distribution package if one exists. Arch Linux and derivatives can install one of the AUR packages, and FreeBSD users will find it in the ports tree. In any other case, you build it from source, and there is a `docs/build.md` page for that.

What you should not do is install from pip, and the README explains why in the first person. The maintainer states that they are not the creator of the project and do not maintain it on the Python Package Index, that the version there is outdated, and that they cannot support it. The same reasoning extends to third-party packaging methods such as Snap and AppImage, where the maintainer says they are not affiliated with those services and cannot guarantee the functionality or version provided through them, and that issues with those methods will not be supported.

The practical instruction in the README is blunt: if you ask for help with one of those installs, you will be asked to install the distro package or build from source before further help is offered. That is a maintainer drawing a boundary around what they can stand behind, and it is worth respecting before you file a first issue.

The source tree supports that workflow. The project metadata declares `requires-python = ">=3.8"` and builds with setuptools and wheel, and `setuptools_scm` is configured in the build metadata. The `pyproject-3.8.patch` and `setup.py.legacy` files exist to keep the build working on older Python versions, and the `requirements_pipx.txt` file is there for the pipx route, which is a different thing from installing into a shared Python environment.

The ten day update check and the log file a bug report needs

PyRadio checks for a new release every ten days, and if one exists it shows a message asking whether to proceed with the update. The update path is only available when the program was not installed as a distribution package, because a package installed from a distribution repository is the distribution's to update or remove, as the packaging documentation explains.

That is a small design decision with a reasonable rationale. If your distribution ships PyRadio, the maintainer of the distribution decides when the version changes, and the in-app updater would conflict with that. If you built from source, there is no one else to update it, so the program does it for you.

The bug reporting process is similarly specific. The README asks that a report state at least the PyRadio version, the Python version and the method of installation, whether built from source, from the AUR or otherwise. It also asks for the log file, and gives the exact way to produce one:

bash
$ rm ~/pyradio.log
$ pyradio -d

You remove the old log, start the program with the `-d` flag, reproduce the problem, and then exit PyRadio normally so the log is written. Attaching `~/pyradio.log` to the issue is described as really useful. This is a better bug report process than most small projects have, and it takes a minute to follow.

The version, the Python version and the install method are exactly the three facts that decide whether a maintainer can reproduce a report, and it is worth noting that the install method matters here specifically because the pip and Snap installs are unsupported, so a report from one of those installs starts at a disadvantage.

Themes, station registers and playlist validation

The parts of PyRadio that are not about audio are the parts where a terminal application can be more capable than its graphical counterparts, and the feature list groups them together.

Theming is the clearest case. A theme is a set of curses colours and attributes, the program ships a number of them, and the documentation explains how to write your own. On a terminal you can restyle the entire interface without a theme editor, because the theme is a text file.

The station editor lets you add and edit stations, and it includes CJK character support, which is a specific piece of engineering rather than a checkbox. The project credits CJKwrap by Florent Gallaire, a library for wrapping and filling UTF-8 CJK text, and lists code from ranger as well. Wrapping wide characters in a fixed width curses layout is a genuine problem, and the credit shows it was solved by borrowing a library rather than writing one.

The station register feature is described as vi-like, which fits the overall design. A vi user expects registers to hold text for later reuse, and PyRadio uses the same idea for stations, so a station you found once can be recalled by a register name rather than searched for again.

Playlists are supported through M3U files, with a dedicated page in the documentation, and there is playlist validation support, so a malformed playlist produces a clear message rather than a silent failure. On the station side, the TODO list records a completed item for notifying the user that the package's stations.csv has changed, which is the kind of detail that only matters if you are paying attention to how the program manages its own data.

Remote control server, OS media controls and what the packaging reveals

Two features extend PyRadio beyond the terminal it runs in. The first is a Remote Control Server, which lets another program control the player. The second is OS media controls, documented as MPRIS, SMTC and Now Playing, which is how the play and pause keys on your keyboard or headphones reach the player.

The media key support has a platform specific requirement that the README calls out: `dbus-next` on Linux is required to enable MPRIS. On other platforms the equivalent integration is handled by the operating system's own media session mechanism. This is the clearest example of the general pattern in this project, where the terminal is portable but the surrounding integration is not.

The packaging metadata also reveals a second entry point. Alongside the `pyradio` script, which maps to `pyradio.main:shell`, there is `pyradio-client`, which maps to `pyradio.main:run_client`. That is the command line face of the remote control server, and it is a hint about how the feature is meant to be used, from another program or from a script.

The package data tells you the rest of the internal structure. The wheel includes `pyradio`, `pyradio.icons`, `pyradio.keyboard`, `pyradio.scripts` and `pyradio.themes`, which maps onto the four feature groups in the README: the station icons, the key binding machinery, the helper scripts and the theme definitions. The `scripts/` directory in the repository also includes the script that inserts tags, chapters and cover art into recordings, and that needs MKVToolNix command line tools. The README is precise about the condition here: MKVToolNix is optional if you use MPV or VLC, and mandatory if you use MPlayer.

On Linux there is one more small integration to know about. PyRadio needs a resource opener to open directories and html pages, and it looks for `xdg-open`, `gio`, `mimeopen`, `mimeo` and `handlr`, in that order of detection. If you use a different one, you can declare it in the configuration window.

Where a terminal radio player is the wrong tool

There are clear cases where PyRadio is the wrong answer, and they are not about its quality.

The first is a machine you do not control. If you need a radio player to exist on a work laptop, a school computer or a shared server where you cannot install a distribution package and cannot rely on mpv being present, PyRadio is a poor fit. The same applies to a container, where there is no meaningful screen to draw a curses interface on and no audio device to play to.

The second is any requirement for a graphical interface or for a service that runs headless and quietly. A remote control server is not the same as a background daemon that plays a stream on a server, and a curses application is not going to feel right to someone who wants a compact window on their desktop.

The third is the maintenance trajectory, and here the dates are what they are. The last push to the default branch was on 2026-05-07, and the recent releases are 0.9.3.11.31 from 2026-05-04, 0.9.3.11.30 from 2026-04-23 and 0.9.3.11.29 from 2026-03-28. The releases are frequent and the version number has not left the 0.9 series, which tells you the project is in maintenance mode with a steady stream of fixes rather than in a phase of new features. The TODO list in the README reinforces that, with the checked items referring back to versions 0.8.8.3, 0.8.9 and 0.9.0.

The licence is MIT, which is permissive and requires only that the notice travel with copies of the software. For a script you run on your own machine that raises no question. If you wanted to ship PyRadio inside a product or a commercial appliance, the MIT terms would be straightforward, but you would still be responsible for the GPL and other licensed components in the wider stack of player and codec software that the project expects you to have installed separately.

The real alternative approach, for comparison, is using the RadioBrowser service directly with your own preferred client, or running a dedicated player such as mpv with a playlist file. The difference in approach is that PyRadio gives you a browsable, searchable, themed interface over the whole directory, and the alternative gives you raw streams and whatever your player already does. If you spend your time in a terminal, PyRadio is the better experience. If you only need one stream to play, it is more machinery than you need.

Editorial conclusion

Adopt PyRadio if you want internet radio in a terminal, you already have a local player such as mpv or VLC, and you like a vi-like interface with a searchable station list and the RadioBrowser directory. Do not adopt it if you need a packaged, dependency-free binary on every machine, if you are on a platform without curses or without a supported player, or if you want a graphical interface. Verify three things first: that your distribution has a PyRadio package or that the source build works with Python 3.8 or newer, that a supported player binary is on your path, and that on Linux you have dbus-next installed if you want MPRIS media key support. Then check the version, because the last push was on 2026-05-07 and the newest tag is 0.9.3.11.31.

Frequently asked questions

What does PyRadio need to play audio?

It needs MPV, MPlayer or VLC installed and on your path, since PyRadio drives an external player for the sound. On Linux, dbus-next is also required to enable MPRIS media key support.

How do I install PyRadio?

The README recommends a distribution package where one exists, such as the AUR packages on Arch Linux and derivatives or the ports tree on FreeBSD, and otherwise building from source with the instructions in docs/build.md. It explicitly asks users to avoid pip, Snap and AppImage, which are unsupported and outdated.

How do I get a log file for a PyRadio bug report?

Run `rm ~/pyradio.log` and then start the program with `pyradio -d`, reproduce the problem, and exit PyRadio so the log is written. The report should also state the PyRadio version, the Python version and the method of installation.

Does PyRadio support internet radio station directories and playlists?

Yes. Pressing capital O opens the RadioBrowser online directory, and M3U playlists are supported with playlist validation, both covered by their own pages in the documentation.

What is the current PyRadio version and how active is the project?

The version is 0.9.3.11.31, with recent releases on 2026-05-04, 2026-04-23 and 2026-03-28. The last push to the master branch was on 2026-05-07, and the repository is not archived.

Official sources

  1. coderholic/pyradio on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/coderholic-pyradio.svg)](https://hysenlabs.com/projects/coderholic-pyradio)

Was this useful?