hacking

Raspberry Pi as a music server

It was really easy to do, once I realised how easy it was to do!

Since my beautiful Raspberry Pi first arrived (and if you don't know what one is, then go click!) I had sunk a lot of time into trying to get it to work as a music server with the off-the-shelf media distributions like Raspbmc. Every possible route seemed to end in niggles and complications, though; they were compounded by the fact that I don't have a HDMI monitor or old TV to plug the Pi into.

More recently, I learned about the music player daemon (MPD) on Linux machines, and wondered if this would provide me with a decent solution: get the lowest layer sorted, and then worry about the graphics later. The most comprehensive guide I could find still felt over-complicated; especially for anyone who might not want to, say, set up an NFS client at the same time (!) or "change[d] the main user name from pi to dockes" (!!) And even then, the guide spent more time on setting up a fixed IP address than actually getting a graphical interface working, which surely is the "wow" moment for most people.

The steps below will hopefully lead you to that "wow" moment, based on my own experience and some of the important and useful points distilled from that guide. I'll assume that you've got your Pi connected to the network, a power supply and the audio plugged into something: I won't cover that here.

Basic Pi software setup (1/3)

You'll need to download the "Raspbian" distribution of Debian from the Pi website, and get it onto an SD card to act as the Pi's hard drive. I won't cover that here either, but here's a setup guide for Raspbian.

Once you've booted the Pi, you'll then need to SSH in. Raspbian tries to call itself "raspberrypi.lan" on the network, so at a command prompt on your laptop or desktop, run:

ssh pi@raspberry.lan

If that doesn't work, then your router might be causing you problems (I've only tested this on Speedtouch and Technicolor routers.) The exact solution will depend very strongly on your router; as there are so many different makes and models, then - as you might have guessed - I can't cover that here!

Otherwise, enter the password when prompted. If you've never SSHed in before, run the configuration manager:

sudo raspi-config

In this "graphical" configuration manager, set the following:

  • expand the disk space to fill the whole of your SD card
  • get the manager to install the most recent version of itself

Finally, run the following to update the package repositories, upgrade all your packages, and reboot the Pi. This will ultimately kick you out of your SSH connection:

sudo apt-get update && sudo apt-get upgrade
sudo /sbin/reboot

Your Pi will rapidly reboot and you should be able to SSH back in, less than a minute later.

Installing MPD and playing music (2/3)

Installation

SSH back into the Pi, and run the following to install mpd and two command-line tools for talking to it. You can install ncmpc or ncmpcpp (the "pp" I think standing for "plus-plus" or "one bettter than ncmpc):

sudo apt-get install mpd mpc ncmpc

mpc is a simple type-a-command tool, where you type textual commands one at a time; ncmpc(pp) has on the other hand a textual "GUI", which works over SSH, and looks a bit like old "graphical" packages from the early 1980s.

When mpd starts, you might get an error a bit like the following:

[....] Starting Music Player Daemon: mpdlisten: bind to '[::1]:6600' failed: 
Failed to create socket: Address family not supported by protocol (continuing 
  anyway, because binding to '127.0.0.1:6600' succeeded)
Failed to load database: Failed to open database file "/var/lib/mpd/tag_cache": 
  No such file or directory

As far as I can tell this is something to do with the Pi's IPv6 networking configuration. The changes below will make it go away!

Configuration

Edit mpd's configuration file: I'm comfortable using vi; but if you can't cope with it, you can use sudo apt-get install ... to install a better editor, like nano or emacs.

sudo vi /etc/mpd.conf

In the configuration file, you want to find and then change the following entries:

music_directory         "/change/this/to/where/your/music/will/be"
...
playlist_directory	"/change/this/to/where/your/playlists/will/be"
...
bind_to_address         "any"

The first two directories can be anywhere on the Pi's hard drive (the SD card, remember!) With that new configuration in place, you should restart mpd:

 
sudo service mpd restart

When you do so, you should also hopefully find the "failed" error message I noted above is no longer visible.

Music

The only other requirement for those directories is that the playlist directory needs to be writeable by mpd. This is because when you ask mpc or another graphical client to add something to a playlist, it asks mpd, which adds it on your behalf: so it's really mpd that's adding the entry. It's not the most secure option, but you can run:

chmod a+rwx /playlist/directory/location

to make the directory writeable by other users. If you want a more secure option, just ask and I'll put something in the comments below.

If you now want to transfer a lot of music en masse into these directories, you can always unplug the Pi, remove the SD card and insert it into your laptop. You should then be able to find the relevant subfolder on the card, and copy your music across into it as if it were an SD card from a camera or portable music player! Alternatively

Oh, one more point: as far as I can tell, mpd doesn't check for new tracks unless you tell it to. So if you add any new music by any means, you need to tell mpd to update its records via a tool like mpc e.g:

mpc update

Now, if you run mpc or ncmpc, they'll spot your new tracks.

Working?

Anyway, if you've got to this point, you should have a running music server, playing music out of your audio socket. But there's one more step before we get to the "wow" moment!

Controlling your music server from a mobile, tablet or other laptop (3/3)

The best bit is that, if you can SSH into the Raspberry Pi, then you (and any other devices connected to the same router) can also use a nice graphical client to access it! There are loads of clients which "talk MPD" so I've just picked three:

  • Android: Droid MPD (free)
  • iOS: MPoD (free: I think a paid-for version has e.g. better display on iPads.)
  • Linux: gMPC (free; requires GNOME; works fine on Unity)

Specify "raspberrypi.lan" in these apps and they should be able to access it, if everything else above went OK. Moreover, if you don't like any of these apps, and you know how to set up a webserver, your next move could be to download e.g. a PHP application and set that up. But setting up web applications on a Pi is probably a whole other blogpost!

Anyway, this worked really well for me. I'm listening to it as I type. Hope it works just as well for you!

Buying a laptop cover without the laptop present

It's like a wonderful logic puzzle, solved by expanded plastic foam!

I need a laptop cover for my laptop. One of those close-fitting sleeves. The only problem is, my laptop's a weird shape: not only does it have a 16:9 aspect ratio, but it also has an extra-large battery sticking out at the back.

That's not the only problem; the other problem is that when I go shopping for a sleeve this weekend I don't want to have to carry my laptop around with me. So either I guess at the right dimensions, or I make sure I buy big.

... Or... I take the expanded plastic spacer that came with my wife's laptop sleeve, and cut it to size! The bits that I cut off, I can glue on the top to increase the depth (it's a chunky Dell beast, you see.) and if I arrange the bits really carefully, like this:

Magical DIY laptop spacer-cum-laptray

... then the resulting assemblage of plastic foam can be carried with minimum heaving around Oxford city centre looking at laptop bags; but afterwards it can also double as a makeshift laptop tray, for use when sitting on the sofa or in bed! The space underneath means the fans should be kept fairly clear, to do their whooshing thing when they need to.

I've looked at a few laptop trays and none of them seem amazing: I could really do with that clearance underneath. But to do that properly, you have to have a tray that's built especially for the footprint of your laptop. Well, now I have that.

What I need next is a sleeve.

Private upload and private download almost work fine together

And where they do, it's because of a bug.

One of our clients' Drupal sites is already using Webform Protected Downloads to restrict access to file attachments. This module depends on Private Upload, although there is - confusingly - another module called Private Download that does something very similar: runs files stored in certain directories through PHP, so that Drupal can check whether or not the visitor and their context permits them access.

Because the client is moving to a slightly different setup, including taxonomy- and role-based access control using TAC Lite, then they need both of these "Prviate *load" modules in place at the same time. Rather neatly, we've found that they don't conflict at all: except for one bug, which you might even manage to avoid. 

Each module has a configured subfolder, which it maintains, and for any file in its subfolder, the module makes the decision. But Private Upload is over-generous in its decision about what counts as its files: if its subfolder is e.g. "private", but Private Download is using "private_download", then Private Upload spots that the latter begins with the text of the former, and assumes that they're its files too! That is, Private Upload checks for files beginning "private...", not "private/...."

Quick to fix, if you spot it before you have installed and are running both modules: just make sure that the folders have wildly different names. Or apply the patch I submitted.

RobotsTxt, robots.txt and /robots.txt

The RobotsTxt module effectively requires a hack to Drupal core in order to function. This is because core Drupal contains a static robots.txt file, and webservers like Apache are configured by Drupal’s .htaccess file to serve static files preferentially to asking Drupal for the content. Every time Drupal is upgraded (or you deploy the site to a new staging or development instance), that hack has to be repeated.

One solution which Johan hit upon a while ago was to patch Drupal’s core .htaccess file, to send any request beginning /robots.txt to Drupal rather than serving any file on disk. It still constitutes a hack to core, but as a patch file accessible at a URL it can be incorporated into e.g. drush make files, and applied automatically when Drupal core is upgraded.

The patchfile-based hack is a big improvement, but it still leaves the RobotsTxt module complaining that there’s a problem. This is because it checks for the robots.txt file on disk, not for the /robots.txt URL, which is the real acid test for whether the module is working properly. So now we’ve also added this patch for robotstxt_requirements(), which checks the URL instead.

Blog category:

Our Drupal Ladder learn sprint

Last weekend, ten Oxfordshire Drupalers did a learn sprint at the Torchbox offices. I’ve written a more complete discussion over on the work blog.

Drupal Ladder learn sprint: pair tuition

We had a great time: it was a gloriously sunny day, which helped, as we were able to eat lunch (sponsored by Torchbox) on the lawns next to the office. But what was best is that the day was so productive: we all ended up learning together, and by the end of it we could all contribute to Drupal on the issue queues.

Thanks, Drupal Ladder project!

Programmatically executing a 2.x View

TL;DR: don't do it, as such! Execute a display instead.

TL;DR: don’t do it! Execute a display instead.

Drupal Views are a good half-way house between user-friendly elegance and writing the SQL yourself. With this in mind, you might want to use them as a robust database API in your own code: you don’t need to think about precisely what’s stored in which table, but execute the view instead.

Working out precisely what you have to do to run a view isn’t straight forward. This now elderly post on Earl “Views” Miles’ blog provides some clues, but only by using page-display rendering as an example. Ideally, we want to avoid running our view through the whole theme layer, as that’s just lost CPU cycles. So what do we do to run our own view?

It turns out to be 90% easy, but 10% ever so subtle. Here is the usual stab, based on Earl’s example:

$view = views_get_view('MY_VIEW_NAME');$view->set_arguments(array($my_first_arg, $my_second_arg, ...));$view->set_display("DISPLAY_NAME");$view->execute(); // - this line is wrong. 

However, that doesn’t quite work. The annoying thing is that it almost works; it just doesn’t quite work. For a start, the number of items per page remains at the default, 10. This is a clue that something else needs to be invoked. But what?

Following that clue, go to the view’s own edit page and click preview. You should see that this preview does indeed respect paging. So what gives? Try invoking debug_backtrace() in View’s set_items_per_page() method, and the devel dsm() function to dump out the contents into Drupal’s messages area.

When you click on “Preview” again to refresh it, you should find that the backtrace includes a call by $view->preview() on $view->pre_execute(), and this is what calls the method to set the paging.

The only other way to call the pre-execute function? $view->execute_display(‘DISPLAY_NAME’). It’s slightly confusing and leaves you with the worry that there might be a pre_execute_display() method that you’re also somehow omitting to call…. Also, DISPLAY_NAME ought to default to, well, “default”, but when we omitted it, paging limits were once again not respected.

Here’s the correct code:

$view = views_get_view('MY_VIEW_NAME');$view->set_arguments(array($my_first_arg, $my_second_arg, ...));$view->execute_display("DISPLAY_NAME");

Your results should be available in an array called $view->result. (note: not singular!) This should respect all paging/offset settings for your display, although of course if you actually want to retrieve page 3 of your results, you’re going to have to do a bit more programming!

Blog category:

Removing checked-in client data from a git repository - permanently

During a recent migration, we checked in some client data to the sites/default git repository. This was a mistake: not least because the client’s data was some four or five times the size of the rest of the rest of the codebase; but also because there were non-ASCII characters in some of their filenames (“Pannetoné”, anyone?) These were playing havoc when they were on folders shared between a Linux Vagrant box and a Mac OSX host.

Removing files permanently from version control means removing them not just from the current revision, but also rewriting every revisions in the repository so they’re not there either (otherwise Git keeps them hanging around in its object repository, in case those old revisions are ever checked out again.) While there are lots of fragments of solutions online, very few of them encompassed the full complexity of our requirements: many branches, many tags, all needing to be preserved, along with trialling the changes by pushing them all to a temporary remote repository.

Our solution to this problem has ended up a little more long-winded than some, but it’s safer and works harder to preserve the integrity of the version history; when we work on behalf of clients, that’s our biggest priority. And applying this to a 27MB repository clone reduced its size to under 6MB!

Blog category:

What happened at the first Refresh Oxford hack day on Saturday

We built stuff that works, is what happened. Apparently, this is rare for a hack day.

Yesterday I went to the inaugural Refresh Oxford hack day in the Incuna offices. It was great.

The local initiative is part of "Refreshing Cities," an attempt to provide vitality to local creative and technical culture, especially in the field of "new media," which one day we'll probably just call "media." As I've spent the last four years organizing the Oxford Geek Nights to do this very thing within the geek-social space, I can only applaud the idea.

The start of the hack day saw dozens of people present: a decent spread of designers, developers, UX/accessibility experts and similar webby folks. It was useful to begin immediately after another first, the inaugural European jQuery conference, also in Oxford; the conference brought a lot of both attention and attendees to the event. Although, the large amount of booze available at the conference means that a lot of people didn't turn up till considerably later; if indeed at all. 

For the first hour or so, we were all free to propose projects to everyone else. The idea was that these should be ideas that could either: be begun and brought to a fun if not necessarily successful conclusion in a day; or that were more long-term, already underway, but needed a day's worth of work from a few people to yield real returns. While we did a bit of horse-trading, we also ate pastries and drank tea and coffee.

Henry, Suzie and I formed a team of frontender, builder and programmer respectively for our own project and came up with a plan for development. Lunch turned up as we started work, and then... well, the next seven hours or so are frankly a bit of a blur. A fun, exciting blur; but a blur nonetheless, as we dipped down below the surface of our project and hammered away at it. By the end of it we had a cute little application with a server and a Chrome browser extension that even I was surprised actually worked (despite Henry's attempts to break it just before we were ready to show it to other people.)

We all finished with pizza, a demo, and then beer. Other demos included:

  • an in-browser horizontal-scrolling game with cats
  • work on making the first volume OED searchable through OCR
  • a prettifying Django views inspector 
  • and an attempt to script kinetic typography

In short, a pretty varied bunch of really neat one-day efforts from everyone. And we also got to meet other like-minded local geeks and find out what other people were up to in the city and its environs. This coincides completely with the whole reason I run the OGNs: geeks are paradoxically both shy and social animals; so encourage them to meet up with each other once in a while, overcome that initial barrier of shyness, and magic happens.

The all-important social aspect aside, it's astonishing what magic people did come up with, given only a day to work on it. Incuna were a really welcoming bunch and made everyone feel at home, and gave us just the right amount of herding: thanks to their foresight, most of the projects we worked on are now available via the Refresh Oxford github account, if you're interested in looking at some of our code. It ain't pretty; but if Rome wasn't built in a day, then these projects were. In your face, Rome.

Ubuntu Linux on a Macbook

'Cause baby, if it feels so right. How can it be wrong? 

Feast your eyes on this:

Ubuntu Linux on a white Macbook

No, it's not photoshopped. What you see is indeed one of Torchbox's white Macbooks, running Ubuntu "Lucid Lynx" Linux. A few years ago, when I was looking for a new work laptop, Tom suggested in a moment of madness that I could get a Mac and run Linux on it. At the time I thought it was the silliest thing I'd heard of. Imagine!

Fast forward two and a half years, and the enormous Dell brick that I bought has started to become more of an annoyance than anything else - too big, too heavy, built-in mouse's buttons broken, battery frequently flickers down to 50% capacity - and it's time to decide whether I want to switch to another existing office laptop before some of our new hires arrive. That idea of Tom's (yes, Tom, if Stewart asks then it's your idea) strikes me again. Could it be possible?

In the end, it was almost ridiculously easy: after a fair bit of hassle resizing partitions; I managed to find relevant documentation online; the Ubuntu 64-bit Lucid Lynx "Live CD" booted the machine straight away so I could confirm (a) it worked and (b) the things nobody expected to work, didn't work; the install sequence took about ten minutes; and the solutions to post-install issues were exactly as documented.

There were only two major problems that dogged me much of the way. Each of them is somewhat stereotypical of the respective community or technology involved:

  1. As mentioned above, OSX/Boot Camp steadfastly refused to change partition sizes on the machine. A graphical interface took me through some cute wizard with progress bars, then summarily told me I'd have to back up the machine and reinstall OSX. Then the OSX install disks said that I couldn't install OSX on this machine. What they both should have said was "Use GParted: it might not be as pretty as they make Mac apps, but you'll be able to work your way through using granular controls we won't let you touch." This is evidence of the standard internet trope OSX as a tamper-proof sealed unit.
  2. Ubuntu's documentation is an absolute rat's nest. I can't even find the comparison matrix of Macbook and Macbook Pro machine types that leads you off into the relevant documentation pages. What I can tell you is that you'll need the catchily named "MactelSupportTeamAppleIntelInstallation" for most of your initial setup and installation, and "MacBookPro" for Macbook Pros or, er, "MacBook" for Macbooks, or Mac Books as the wiki would have them. This is evidence of the standard internet trope Linux as an unnavigably documented hobbyist's pursuit.

But really, if I were to make too much of either of those problems in this context then it would be cavilling. Partition resizing is easy to get horribly wrong; and that ridiculously complete level of documentation didn't even exist two years ago.

This has been a trial installation really, as I hope to eventually get a hand-me-down Macbook Pro to run it on. But this finished article has functioning wifi and a working webcam (both of which are proprietary monsters), great sound and the most beautiful DVI-powered second display I have ever seen. After coding on two huge LCD displays for nearly two years, I would still gladly switch to a wee Macbook monitor, typically closed and connected to just one of those large LCD displays. DVI seems to make all the difference over VGA, although I would have never believed it.

Now, of course, I want a Macbook for home use. Running Linux, of course: but maybe this was Tom's idea all along. Mactel Linux as a gateway drug. I can hold out, though; at least, I can wait for them to sort out package management first.

What you need to know about Drupal views

Between Views and custom code is a no-man's land. Here's how to pick your way through it.

Every content management system needs its query builder—an application which creates customizable lists of content elements and present them in a similarly customisable way. Customization will be typically through an admin interface on the website, and the query builder can be as basic as a text box for SQL or as complex as a many-layered GUI across multiple webpages. Drupal, for its part, has Views. D5 has Views 1, D6 has Views 2, and it looks like the forthcoming Drupal 7 will have Views 3.

However, as the criteria for list-building get more and more complex, there will come a point where custom code will produce the exited result far more quickly and efficiently than Views. The problem for the developer is: while simple lists are obviously candidates for Views; and riotously tangled layouts are obviously candidates for your own modules and SQL; how do you cope with the middle ground? How can you tell from the outset that a particular problem will land you in a Views-only cul-de-sac?

Well, I contend that the individual developer needn't worry, so long as he's clued up about developing with, not outside, Views. I reckon that the middle ground can almost always be bridged by Views augmented with custom code; unless you're completely convinced from the start that, say, the logic of what you want is not representable in a query builder, you can start with Views and tweak with customisations later.

But to be sure you can extricate yourself from any small to medium tiger traps that "Views+your spec" might drop you in, it's wise to know in advance the full range of tools at your disposal. Here are five of what I consider the most important tricks for building a complex Drupal view.

  1. Views themeing  Views has a very modular set of Drupal theme files. The markup and presentation of individual fields, rows of fields, and whole views of many rows can all be modified on a per-view, per-view-format or even cross-site basis. In a particular view's admin GUI, you can see an entry marked "Theme: Information." If you click on this, it will tell you what template files the view will try to use, and what files it's currently using (in bold.) You can copy these files across from the module directory to your theme and rescan to use them; you can even rename them to be specific to the current view or formatting options, and when you rescan the directories, Views should spot the new files.
  2. Addon modules  There are a number of extension modules for views which will very quickly improve view presentation or data flexibility. At the one end is Semantic Views, which allows you to present certain fields in your views with more semantic markup: titles can be h2 elements; contact details can be in address elements, etc. At the other end of the workflow, close to the database, is the Views Or plugin, which lets you swap the normal views filter AND logic ("all items must be published AND have type=blogpost") for a more inclusive OR logic ("all items must have type=blogpost OR be less than three weeks old"). If you're not sure whether there's an addon module for you, ask on the #drupaluk IRC channel.
  3. Views as a backend  Several third-party modules use views as an adjunct: that means that while the module itself is doing something apparently clever with your content, it's secretly using a view to manage most of the hard work. If you want to maintain arbitrary admin-sortable lists of content, Nodequeue provides a nice interface for doing so. But behind each nodequeue sits... a Drupal view, and a plugin which ties the nodequeue database table to your nodes to produce the required results. Tagadelic, a module which produces tag clouds for e.g. your recent blogposts, has over the years moved from a standalone module (which still exists), to a Views style plugin, so you can build the initial tags view yourself and activate Tagadelic styling and popular-tags filtering once you're done.
  4. Views hooks  The workflow for views is like the workflow of Drupal itself in miniature: as such, it has its own set of views-specific hooks, including hook_views_pre_render and hook_views_pre_build. All the Views hooks are documented on drupalcontrib.org. So, learn the basic page-view flow, from a blogpost by Mr Views himself, Earl Miles. Pick it apart. See what each bit does in the code. You should eventually be able to find the views hook you want in the code, and be able to modify the view object, its compiled SQL, the results returned, and even the eventual output, all in your own modules.
  5. Writing your own plugins  A Views plugin is less complicated than you might fear. There's not a great deal of easy-to-find, easy-to-read documentation out there about Views plugins, but try not to let that put you off. A plugin consists basically of a module, a hook function (or two) and a PHP object: the rest is just detail and theming! While that sounds a bit glib, it has some merit: look at the plugins for such modules above as Semantic Views and Nodequeue, and see how they all relate back to an object in a .inc file and a template in a .tpl.php file. You can extend an existing plugin using standard PHP class syntax, and develop it piece by piece by overriding methods one at a time. Views plugins are incredibly powerful, more so than using configurable third-party modules or just interrupting the current view using a Views hook. They get your code right into the heart of a given view's workflow and let you do (almost) whatever you want. Remember to clear caches if you get stuck: you might even need to resort to a "TRUNCATE cache" at your MySQL command line if your changes don't seem to be having an effect.

If you've started building your listing page with Views, but the spec has ended up getting more complicated, try each of the five solutions above in turn. When the problem at hand suddenly gets a whole lot more complicated, escalate your solution's complexity by moving another step down the list!

There's obviously a lot more to developing with Views than a single blogpost could ever really summarize without turning into an extended essay. But there's a lot more documentation out there—although of a pretty sprawling and hard-to-navigate sort—and the tips above should hopefully give you pointers both for where to start your extending of Views, and also what to google for when you get stuck. Have fun and good luck!

Pages

Subscribe to RSS - hacking