Distracted Attention

It’s all about the ratings…

I began Pepper to create an app that would let me find my favorite videos fast. Pepper does this is by letting you add a rating to each video file or by creating playlists.

Recently I’ve begun running into a few headaches.

Design Decisions

Pepper isn’t a Finder replacement. As such, there is no support to browse the live filesystem. You have to specify which directories you want visible. That sounds similar to iTunes…

However, the way iTunes implements that is by copying all the music in the added folder to it’s own location on your computer: ~/Music/iTunes

I made a design decision at the start to avoid file modification as much as possible. That meant leaving files where they were. Information about each file, such as ratings and playlists were to be stored in the database. The primary key for each video was its on-disk path.

Handling Changes

Because Pepper doesn’t have complete control over the directories where the files were added, it needs to monitor and detect when files were added or removed. This is implemented using the new FSEvents framework in Leopard.

When changes are detected, the on-disk files are compared against entries in the database. Files that no longer exist are removed from the database, and new files are added.

Test Environment

In my own personal test environment, I have 300GBs on the iMac, 500GB on an external HDD and 1TB on a Time Capsule (wireless NAS).

The Problem

  1. In Pepper, I add the (Time Capsule) folder Disk1/Videos.
  2. On-disk, the Time Capsule volume is mounted at /Volumes/Disk1.
  3. The wireless network experiences a hiccup and the Time Capsule is disconnected.
  4. My iMac reconnects to the Time Capsule, and mounts it as /Volumes/Disk1-1
  5. Pepper detects the change and removes every file from the database that had a path of /Volumes/Disk1/Videos (which is everything).

Solution So Far

When a filesystem change is detected, Pepper will first check to see if the top-level “Place” is available. If it isn’t available, further checking (for new or removed files) is skipped.

I’ve added a new attribute to the database “relativePath”, and changed the “path” attribute to be transient.

In the Entity, path is created by combining the Place.path and Video.relativePath using stringWithFormat. This means that if the volume mount point changes from Disk1 to Disk1-1, a simple edit of the Place Info will make the files accessible again.

Other Ideas

Ideally, the best way to store persistent data about a file, aka ratings, would be to add the information to a files metadata. There’s already an attribute called kMDItemStarRating that’s purpose built for it.

Unfortunately Apple doesn’t offer a (public) means of modifying a file’s metadata unless you’re the Spotlight importer for the file’s filetype. Unofficially you could use the private MDItemSetAttribute to modify attributes, but if Spotlight is reindexed, all your changes are blown away.

Another option could be to mirror iTunes behaviour and keep a copy of each file. I really don’t want to go down that path, and it really constrains you if your local storage runs out.

Wrapping Up

I suppose this is all good to discover sooner rather than later. Imagine if I’d only developed and tested without consideration of removable volumes. A far larger retrofit would’ve been required down the track. At least now I have a chance to work on a means of gracefully handling volume renaming that doesn’t erase your information when files “disappear”.

Tags: , , ,

Posted by Nick | September 1, 2008 | Filed under Cocoa