How to write your own pipe menu scripts

Marco Fioretti follows up his post about the efficiency of pipe menu scripts with an example of how to write your own customized scripts to put the information you want on your desktop.

Last week, I introduced Openbox pipe menus and presented the four ones that I like best in the official galleries.

What's great with pipe menus, however, is that it is very easy to write your own -- that is to make Openbox manage all the dynamic information that you need. To prove this, as I anticipated in my previous post, this week I'll explain step-by-step how I wrote a pipe menu that lets me read RSS feeds straight from Openbox, without opening any browser or graphical RSS client unless I really want to read some full article.

Such a script has one obvious prerequisite that has nothing to do with Openbox and it's menus: it needs as input plain text lists of news titles and URLs, obtained with some other means. In other words, you must have already downloaded and converted to a suitable, simpler format, the RSS feeds you want to read. Personally, I have recycled for this purpose a command line RSS downloader that I wrote last year for a slightly different purpose, that is converting RSS feeds to HTML format. That script takes two argument: an arbitrary feed name and the URL of an RSS feed. It then downloads that feed and saves its URLs and titles in a plain text file. As an example, when I pass to it the URL for the RSS feed of the Tech Republic blogs: Tech_Republic ''

I get something like this (I trimmed URLs and titles for readability):

Tech_Republic | Comic-Con 2011 highlights: Film, TV |

Tech_Republic | Top 10 lightsaber battles in Star Wars movies |

Tech_Republic | Tech scoreboard, July 29 |

So, let's assume that you have several files in this format in some reserved directory, periodically rewritten from some cron job. How do you transform their content in an Openbox menu-based RSS reader? I do it with this 19 line-script:

       1  #! /bin/bash
       3  RSS_FEED_DIR="/home/marco/.rss_feeds"
       4  echo "<openbox_pipe_menu>"
       5  for FEED in `find $RSS_FEED_DIR -type f`
       6    do
       7    FEED_NAME=`head -1 $FEED | cut '-d|' -f1`
       8    echo "<separator label=\"$FEED_NAME\"/>"
       9    while read line
      10      do
      11        POST_TITLE=`echo "$line" | cut '-d|' -f2`
      12        POST_URL=`  echo "$line" | cut '-d|' -f3`
      13        echo "<item label=\"$POST_TITLE\">"
      14        echo "<action name=\"Execute\"><command>firefox $POST_URL</command></action>"
      15        echo "</item>"
      16      done < $FEED
      17    done
      18  echo "</openbox_pipe_menu>"
      19  exit

Let me show you the final result before explaining the details. If you run the script above at the prompt, you'll get something like this (again, trimmed for readability):

  <separator label="Tech_Republic"/>
  <item label="Comic-Con 2011 highlights...">
  <action name="Execute"><command>firefox</command></action>
But if you "install" it as an Openbox pipe menu script, following the procedure I explained last week, you'll get root sub-menus that are live RSS feeds, like the ones shown in Figure A.

All the script does is to:

  • read all the files in the RSS_FEED_DIR folder (line 5), one line at a time (line 9)
  • extract title and URL of each item of the current RSS feed (lines 11/12)
  • print them to standard output, wrapped in the proper Openbox-compatible markup

The only difficult part here is to know exactly what that markup must be. Studying the code above, you can immediately learn the markup to generate opening and closing statements for each menu (lines 4 and 18), labeled separators (line 8) and menu items that make Openbox launch programs, rather than just display some text. Such items declare inside <action> and <command> tags (line 14) the command that Openbox must execute whenever you click on the menu entry with the associated label (line 13). A command like firefox <URL> will tell Firefox to open up that page, in a new tab if it's already running. If you need them, all the gory details of the Openbox menu syntax are in the Openbox wiki.

What's left? Just one thing. The attentive reader will have noticed that, while the script works perfectly as is, it will generate menus that become too long, that is unusable, as soon as they grow above 20/30 entries. The solution is to split those entries in one sub-menu per feed, by having the script generate the extra markup that has this effect. You can achieve this result by rewriting line 8 in this way:

echo "<menu id=\"$FEED_NAME\" label=\"$FEED_NAME\">"
and adding the command echo "</menu>" after line 16. This will give to each RSS feed its own sub-menu, as you can see in Figure B.

In general, news titles in generic languages may contain some special (Openbox-wise) character that could cause Openbox to not display them. I haven't met such titles yet, but they probably exist. I haven't the space to go into all details here (thought I may do it in a separate post), but should that be your case, you would have to escape all such characters in the titles, right before loading them inside $POST_TITLE. For the moment, I hope I've shown you how powerful, flexible and easy to build Openbox pipe menus can be, no matter what your needs are!