tech

My new MP3 player from Tesco

Until very recently, I was using an iAUDIO M3 as my music player. This is a great little unit, as it plays oggs and mp3s, has a 40Gb hard drive, works well with Linux, and excellent sound quality. However, the headphone socket recently broke, so that if the jack plug wiggles around in it, the sound fragments. This is very frustrating; even more so because as far as I can tell, you have to send it back to Korea to get it fixed. (Unless anyone can suggest an electrical shop in Birmingham UK prepared to do this kind of work? I think it probably just needs a bit of soldering. It's out of warranty anyway, so I haven't got much to lose.)

As an interim solution, I decided to buy a dirt cheap player from Tesco. I got a Technika MP706 with 256Mb of storage for £14.97 (less expensive than my headphones). It charges from USB (battery life is about 4 hours or so - they state 6 hours on their website, and I haven't been monitoring that closely). You can just drop files onto it (like a USB stick): no need for a fancy iPod style interface and it works with Linux. It only plays MP3s, but that's not a significant hardship. Sound quality is decent (not as good as the M3, but it costs less than a 10th of its price). The interface is a bit rubbish, but once you've done the initial, painful configuration, the play and jump buttons are functional if a bit fiddly.

The only thing which is a bit flummoxing is that it takes forever to unmount (on Ubuntu at least). Don't be tempted to unplug it while unmounting, because this seems to leave it in an unusable state until you plug it back in, copy your files again, and unmount it properly. Perhaps the internal write speed is really slow or something (I know bugger all about USB).

It's a really good buy, and so cheap it's pretty much disposable, so I'd recommend it.

In fact, has the world gone mad?

I haven't commented on Microsoft's patent application on web syndication before, but having actually looked at the application, I can hardly believe the sheer gall of it. I am against software patents in general, but these applications surely take the biscuit. Am I missing something? As far as I can see, they are attempting to patent Bloglines (for starters) and every other RSS feed aggregator, del.icio.us, and the Atom publishing protocol (probably). Surely all of these must count as prior art?

Google goes evil over its SOAP API?

I missed this before Christmas (still catching up in Bloglines), and can't recall seeing it mentioned in any of the blogs I read religiously. This report notes that Google are no longer supporting their SOAP search API, and are instead encouraging developers to move to their AJAX search API. Excuse me, but providing a few widgets which talk to Google and wrap the results inside Javascript objects surely isn't the same thing as a SOAP API? How am I supposed to use an AJAX API from inside a command line application (other than picking apart the requests it makes and reconstructing them manually myself)? Thankfully I'm not using the SOAP API myself (and never will be, now), but I'm sure there are more than a few developers who are mightily annoyed by this development.

Ruby Tuesday: Rendering and redirecting in a single Rails controller action

Update: I knew there had to be a better way! Rich (see comments) mentioned render_to_string, which I hadn't noticed before (plus I sort of ignore all the render_* methods, as I assume they are deprecated). This is a much neater solution, making the controller look like this instead:

class FilerController < ApplicationController
  def index
  end

  def create_file
    @text = params[:text]
    out = render_to_string(:action => 'wrap')

    filename = File.join(RAILS_ROOT, 'tmp', \
    'files', params[:filename])
    File.open(filename, 'w') do |f|
      f.write(out)
    end

    flash[:notice] = "File created"
    redirect_to :action => 'index'
  end
end



This is probably of marginal interest, and also may be against the laws of nature as far as Rails is concerned. But recently I had a requirement to render a Rails view, save it to a file, then redirect the client to another view, all within a single controller action. (To give some context, this was necessary in an application which writes HTML files to S3. What I was doing was rendering a list of links pointing to the contents of an S3 bucket; then putting the index page itself onto S3. This way I can stick a load of files onto S3 then auto-generate an index page for those files, which in turn is also hosted on S3. I like the self-reflexivity of this :).)

As an example, consider a controller with similar requirements: it has a create_file action which renders another action to get some HTML, saves the resulting HTML to a file in tmp/files, then redirects back to the index page. (I've taken S3 out of the equation for simplicity's sake.) The index action for the controller just displays a form to fill in some text (which gets wrapped in some HTML) and a name for the new file. The full controller definition looks like this:

class FilerController < ApplicationController
  def index
  end

  def create_file
    @text = params[:text]
    html = render(:action => 'wrap')

    filename = File.join(RAILS_ROOT, 'tmp', \
    'files', params[:filename])

    File.open(filename, 'w') do |f|
      f.write(html)
    end

    flash[:notice] = "File created"
    redirect_to(:action => 'index')
  end
end

The wrap template (app/views/filer/wrap.rhtml) looks like this:

<div id="wrapper">
<%= @text %>
</div>

The index template (app/views/filer/index.rhtml) looks like this:

<%= content_tag('p', flash[:notice]) if flash[:notice] %>
<%= start_form_tag :action => 'create_file' %>
<p>Text for file:<br/><%= text_area_tag :text %></p>
<p>Filename: <%= text_field_tag :filename %></p>
<p><%= submit_tag 'Create' %></p>
<%= end_form_tag %>

That's the whole application. Note that I've left out all the HTML trappings; and this is possibly the least secure application ever written, as it creates files on the filesystem from arbitrary input. But it will do for a demo.

But when you submit the form with a filename and some text to put into the new file, Rails throws a nasty ActionController::DoubleRenderError error with this message:

Render and/or redirect were called multiple times in this action. 
Please note that you may only call render OR redirect, and only once per action.

It turns out there is a simple way to get round this, by rewriting the create_file action to use lower-level methods (avoiding redirect_to), like this:

class FilerController < ApplicationController
  def index
  end

  def create_file
    @text = params[:text]
    out = render(:action => 'wrap')

    filename = File.join(RAILS_ROOT, 'tmp', \
    'files', params[:filename])
    File.open(filename, 'w') do |f|
      f.write(out)
    end

    flash[:notice] = "File created"

    # naughtily work around the one redirect/render per action
    response.redirect url_for(:action => 'index')
  end
end

This has the desired effect I'm after: the action creates the file, then redirects back to the index page. Though I blush every time I read the code. If there's a better way, please let me know.

I've attached the files for this example below.

Donate to Wikipedia

I'm sure, like me, you use Wikipedia a lot, whoever you are. Or at least it crops up in your search results (normally near the top, in my experience). That's why it's important to donate some money to the Wikimedia foundation, to support its continued existence.

Quod Libet plugins on Ubuntu

I've moved back to Quod Libet from Rhythmbox this week (the only thing I miss is Rhythmbox's "Recently Added" category). One gotcha which took me a while to work out: to use Quod Libet plugins, they have to go into ~/.quodlibet/plugins. Copy them from /usr/share/quodlibet/plugins (which is where they are installed by default, on Ubuntu at least) to that directory and you should be fine.

I also installed some binaries of the new version, even though I am on Ubuntu Breezy: see http://www.ubuntuforums.org/showthread.php?t=131304&page=3 for Ubuntu packages.

Linux Desktop Architecture Meeting (I didn't attend, by the way)

I was really heartened by this article which outlines the recent Desktop Architecture Meeting 3 in Portland, where a bunch of Linux desktop folk got together to discuss how to move Linux on the desktop forward. This is an issue which is dear to my heart, as I use Linux exclusively, both at work and home. Particularly important to me is what was called "sound suckage", something which desperately needs fixing. I have a few issues with sound myself on my Ubuntu (still Breezy, need to upgrade to Edgy soon):

  • Some sound program on my computer initialises esd (the e-sound daemon). Once this is running, it means I can't listen to sound from any Flash movies inside my browser. I use the command line to kill esd, restart Firefox, and everything is alright with the world. Don't imagine my dad could do this, though.
  • For some reason, when I rip to ogg with Grip, the mime type in the properties dialogue for the resulting file in Nautilus reports "audio/mpeg" (even though the file name suffix is .ogg and I thought I was ripping an ogg). If I change the suffix to .mp3, Nautilus goes crazy and plays a stuttering first few seconds of the track. I've switched to ripping to mp3, as oggs were driving me mad. Not sure if the problem is with Nautilus or Grip, here.
  • It's still a pain to get all the decoders working to play mp3s, wmas and all those other hateful formats. Is there any way to make this easier without sacrificing the pure, free OS for the people who want it? I'd be prepared to pay some cash to Ubuntu every year if they could make this simple for me.
  • Just this week, Rhythmbox decided to seg fault every time I tried to play a track. I reinstalled Rhythmbox, cleaned out my settings, fsck'd the external hard drive with my audio on it (in case that was causing the problem), but still the problem. Does Rhythmbox have problems when you have over 5500 tracks? I actually had to switch back to Quod Libet so I can listen to music at all.

Aside from this (which, as you can see, is very important to me), it's also interesting to read about plans to make hardware for support more comprehensive. It still pains me that my laptop internal wireless is not working (though that may be fixed in Edgy - we'll see). Until hardware manufacturers buy in, and you can buy a computer with Linux in PC World, Linux on the desktop will stay grounded. (Though I noticed a PC in Woolworths had StarOffice on it the other day, which I suppose is a start of sorts.)

I'd also like to reiterate a point made elsewhere: why is it I can get 3D spinning windows on my screen, but my wireless doesn't work, external projectors work sometimes and not others, and I have to manually stop sound daemons to use Flash? Although those issues are dull, they are the real barriers to the uptake of Linux on the desktop; not the fact it doesn't look like the Mac UI.

Ruby Tuesday: RSS feeds in Rails

Yesterday, I mentioned I have added RSS feed capabilities to FlickrLilli. I thought it might be worth sharing my experiences of this, as it took me a good couple of hours to iron out the wrinkles and get a valid feed.

Update: Thanks to Thomas Hurst (see comments) for pointing out that I can just use the output from the existing partial and escape it again.

Existing components

I had a lot of code for fetching photos from Flickr and displaying them as HTML: I wanted to reuse these as much as possible. The examples below simplify, as FlickrLilli is a special case and doesn't have a database back-end; for the example, I have assumed a photo database which stores Flickr-like photo objects.

The model

FlickrLilli doesn't use ActiveRecord, but has objects corresponding to photos from Flickr. For the purposes of this example, let's assume a photo actually corresponds to a table in the database called photos, and has a model that looks like this:

class Photo < ActiveRecord::Base
  has_and_belongs_to_many :tags
  belongs_to :owner
  
  # Show tag names in a human-readable string.
  # (Thanks to Tim [see comments] for reminding me of this syntax.)
  def tag_str
    tags.map(&:name).join(", ")
  end
end

And that the model supplies these attributes (which mirrors Flickr metadata on a photo):

  • title
  • description
  • date_taken
  • image_url (the URL to the actual photo graphic file)
  • tags (returns an array of Tag model objects)
  • licence
  • owner (an instance of an Owner model object, with a username and homepage URL)

The standard partial for rendering a photo

FlickrLilli uses a single partial to render a photo as HTML in different contexts (app/views/main/_metadata.rhtml). Paraphrasing a bit, this looks like:

<h2><%=h photo.title %></h2>
<p><%= image_tag(photo.image_url) %></p>
<p><strong>Tags:</strong> <%=h photo.tag_str %></p>
<div class="photo_details">
<p><strong>Licence:</strong> <%= photo.licence %></p>
<p><strong>Date and time taken:</strong> <%= photo.date_taken %></p>
<p><strong>Owner:</strong> <%= link_to photo.owner.username, photo.owner.homepage %></p>
<p><strong>Description:</strong><br/>
<%=h photo.description %>
</p>

The RSS feed generator

Given these two existing components (a model and an HTML partial for a photo), I set about writing my feed generator. It needed:

  1. A controller action to manage the feed
  2. An RXML template for rendering it (RXML uses Builder to generate XML output for controller actions)
  3. A route which makes it convenient to download the raw feed XML as an XML file with a .xml suffix

The controller action for the RSS feed

This was pretty quick to write. Again, using a simplified version for the purposes of exposition, I added the action to my MainController class (in app/controllers/main_controller.rb):

def rss
  # Get the 10 most recent photos
  @photos = Photo.find :all, :limit => 10, :order => 'date_taken DESC'
  # Title for the RSS feed
  @feed_title = "10 most recent photos"
  # Get the absolute URL which produces the feed
  @feed_url = "http://" + request.host_with_port + request.request_uri
  # Description of the feed as a whole
  @feed_description = "10 most recent photos"
  # Set the content type to the standard one for RSS
  response.headers['Content-Type'] = 'application/rss+xml'
  # Render the feed using an RXML template
  render :action => 'rss', :layout => false
end

There are a couple of key things to note here:

  1. The Content-Type header should be set properly for the response.
  2. The RXML template needs to be rendered without a layout, otherwise you get XML wrapped in the controller's layout.

The feed XML template

This uses the RXML template provided by Rails to generate the XML document. There is an example in the Rails documentation, but as far as I can see it doesn't produce a properly-valid feed, as it lacks an <?xml version="1.0"?> declaration. Here's my template, which went into app/views/main/rss.rxml:

xml.instruct!
xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
  xml.channel do
    xml.title @feed_title
    xml.link @feed_url
    xml.description @feed_description
    xml.language "en-gb"

    for photo in @photos
      xml.item do
        xml.pubDate photo.date_taken.rfc822
        xml.title h(photo.title)
        xml.link photo.image_url
        xml.guid photo.image_url
        xml.description do
          xml << h(render(:partial => 'metadata', :locals => {:photo => photo}))
        end
      end
    end
  end
end

Things of note:

  • A guid element is added for each item. This enables blog readers to uniquely identify items, meaning it can detect which items in a feed are new and which have already been seen. In this case, I'm just using the image URL; in the case of FlickrLilli, I use the URL of the photo detail page on FlickrLilli, which ensures the feed only shows items which are new, not updates to existing items.
  • The Time class in Ruby provides a handy instance method called rfc822, which returns a string suitable for use inside the <pubDate> element of an RSS feed.
  • The xml << h(...) syntax directly appends some content to the XML output, attaching it to the currently active element (in this case, the <description>).
  • The partial is rendered using the standard render method, passing the photo in as a local. The whole lot is then filtered through the h method to escape all the HTML. This will result in some parts of the HTML being "double escaped"; however, when decoded by the reader at the other end, it should be proper single-escaped HTML again.

A nice route

Applications like Firefox look at the filename suffix of a downloaded file to determine how to handle it. If we make the RSS feed available at a URL like http://localhost/rss, the downloaded file will be called rss, and some applications won't be able to work out what to do with it.

So it gets properly treated as an XML file, I add a custom route to config/routes.rb:

map.connect '/rss.xml', :controller => 'main', :action => 'rss'

And that's it!

Bonus sample code

Because I'm feeling generous, and because I wanted to check all the above actually worked, I put together a really simple Rails application which fleshes this out and includes a sample SQLite database and migrations. It's attached below. To run it, just use script/server, then browse to http://localhost:3000/rss.xml. When I tested it, it produced a valid RSS feed.

RSS feeds of Flickr Creative Commons material now in FlickrLilli

I tend to use FlickrLilli to do the same search over and over (I use open as this provides good material for presentations on open source, naturally). I decided to hack a quick RSS feed facility into FlickrLilli to support this mode of working. It's just a link added to the search results page, but it means you can get a feed of the Creative Commons images in Flickr matching your query. This is updated in real time (it should be cached really, but like I say, it's a quick hack at the moment). Give it a spin and let me know how it performs. It would probably be best if you didn't batter it every 5 seconds, as it does a live search for every query at the moment. By the way, I am quite surprised that Flickr doesn't provide this facility on general searches, though it does seem to provide feeds for groups and pools (I think).

New version of FlickrLilli

FlickrLilli is a project I've been working on/off with for about a year now. The idea is that it provides a search interface across Flickr's Creative Commons content; I use it myself to source royalty-free images for presentations. It was a really early Rails project of mine, so the code was a bit ropey in places; and I've had many problems hosting it, as it used to be a bit "bursty" and create dozens of HTTP requests very close together (AJAX, don't you know), which made all the hosting I've tried break. I spent a lot of time rewriting the XML parsing to make it more efficient, but still problems.

A couple of months ago I embarked on a major rewrite. This time I decided to remove a lot of the AJAX request load by rejigging the interface, so details for pictures are loaded on request; I also rewrote all the AJAX stuff so it degrades gracefully and works on more browsers (including IE, which was a problem before), using Unobtrusive Javascript. This was the biggest challenge. And I redid much of the CSS so it resizes better (still problematic on really small screens, but I'm no CSS expert); it should also work with all the CSS off in ancient browsers. I've retained the login feature, which enables you to login to your Flickr account and make comments/add favourites from inside FlickrLilli. There are still issues with the Javascript on browsers other than Firefox, but at least it all works with Javascript turned off if necessary.

I've now completed all this, and you can see the results at http://flickrlilli.org.uk/. Enjoy! Let me know if it breaks! (It's only on cheap shared hosting and I had to revert it to REXML, so more than likely it will fall over within a few minutes of me posting this.)

Syndicate content