Efficient Linux Scripting with Fzf and Rofi
TL;DR Here is the internet radio streamer script. Fzf and Rofi are kickass tools.
Little by little, I have been changing the many small interactive scripts I use from antiquated radio buttons and checkboxes to small menus and text fields. Along the way, I have discovered the many fast, efficient, and elegant ways to search and select with two special applications. One is fzf, the command line fuzzy finder. The other is Rofi, which can list the open windows, launch applications, and present menus with fuzzy finding capabilities. Read on to see an example of how fzf and Rofi have improved my workflow, with a script demonstrating their usage.
My Invisible Radio Streamer
When I'm here at the keyboard, whether writing for the web, editing code, or hunting for data on the internet, I am almost always monitoring a favorite broadcast stream. None of my earlier methods were especially efficient: they occupied a lot of screen area and / or took a lot of points and clicks to manage.
Things began to change when I adopted a stronger approach to minimalism and higher quality bash scripting. One nifty script referred to a list of stream urls, took a set of audio parameters, and used the VLC ncurses interface to both manage the playlist and audio stream. Great, but the process was still too slow, with more screen clutter and user inputs than I wanted.
Then came the day I found fzf. It is fast, has plenty of options to refine its functions to what the user needs, and it is simple to implement. Building a menu was a matter of creating a list or array variable, then feeding that to fzf. When an item is selected from an fzf menu, it is input to the next application executing in the chain. Fzf works on the command line.
Rofi, on the other hand, operates as a graphical interface. As with fzf, you build menus by sending lists into Rofi, which renders them as menus. Whatever is selected from that menu is used as an argument for the next application. In some cases, an answer to one question leads to another need for making a selection from items in a subsequent menu.
A script which works with both fzf and Rofi is somewhat more complex than one using either by itself. It needs to discern which tool the user intends to use, then implement the proper command set for either fzf or Rofi. The flow goes as follows:
- Decide whether to operate with fzf or Rofi commands; store the proper set.
- Render the first menu: | play a stream | stop streaming | edit the list |
- If playing a stream:
- Read the list, where each line contains a stream url and the name of the broadcast service.
- Show the user a list of broadcast service names.
- Take the user's selection and open the corresponding url in the player.
- Disappear from view, but continue to stream the audio.
- If stopping a stream:
- Kill the player process.
- If editing the list of stream sources:
- Open the list in Vim
There are two kinds of lists being handled within the script. The simplest is that first one, where the user chooses to play, terminate, or edit available streams. It is contained in a variable called "OPTIONS", with each option itself set in a string variable: "OPTION1", "OPTION2", or "OPTION3." These options are separated by "\n" (a newline).
The other list is read from a file, with each line containing two fields: the stream url and a quoted string which is a plain language description of the stream. When the script reads the file, awk and sed are used to parse and clean up the fields, as necessary.
VLC is used because I am a long time happy user of the software, and the ncurses interface is nicely compatible with automated scripts. You are not limited to simply playing a file in the background. It is possible to use filters to adjust the volume, equalization, or even managge the loudness dynamics of the material. Streams and podcasts are rarely set to the perfect level, having been ripped from videos or set for the wants of their host studio. In the player, I set VLC to run a fair amount of amplitude compression and present a more even loudness to the listener.
Linux can be an incredibly efficient operating system on which we can base out computing tasks. When there is a need to make choices and execute an action of any sort, it is small, light, and snappy applications like fzf and Rofi which help us "get our part done" in minimal time. The rest is all a matter of waiting for the network and our hardware to interact and manage the data.